其实 JDK 中有很多小坑, 我们稍微不注意, 就掉进去了, 然后调了半天 bug, 也不知道为何. 很闹心!
这里说一下, 在Integer中的一个小坑.
看一个小例子:
@Test public void testInteger(){ Integer a = 1; Integer b = 1; Integer c = 128; Integer d = 128; System.out.println(a == b); //true System.out.println(c == d); //false }
运行可以看到输出结果, 就是注释. 可以看到两个 128 尽然不相等! 闹什么呢? 逗我呢?
别着急, 先来看看执行 Integer a = 1; 之后 Integer 会做什么. 从JDK5 之后就有自动装箱和拆箱了. 给 Integer 赋值一个 int 数字, 当然会发生自动装箱, 封装成一个 Integer 对象.
怎么封装的呢? 在编译的时候, 会调用 Integer 中的 public static Integer valueOf(int i) 方法, 然而在这个方法中, 就存在一个小坑.
看一下方法体:
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
IntegerCache.low: 默认的是 -128
IntegerCache.high: 这是可配置的项(-Djava.lang.Integer.IntegerCache.high=200), 默认的值是 127
在编译阶段, 如果将原始类型 int赋值给Integer, 编译时, 就会自动的调用Integer中的valueOf(int)方法(自动装箱)
也就是说:
1. 如果Integer的值在 -128与127之间, 那么这个值就会被缓存, 当你取这个值的时候, Integer类从缓存中取出来直接返回, 比较的是数字.
2. 如果Integer的值不在 -128与127之间, 那么当你取这个值得时候, Integer会为你new一个新对象出来, 这时候比较的是地址, 所以是false
扩展:
1. Boolean类型的两个值 true和false都会白cache.
2. Byte的256个值全部cache在内存中.
3. Short, Long两种类型的cache范围同Integer, 但是不同的是无法调整他们的大小, 代码中完全写死.
4. Float, Double 没有 cache, 在实际场景中 cache 需要自己做.
5. 当 Integer 与 int 类型比较时, 这时候会将Integer自动转换为int类型, 也就是通过调用 intValue()方法返回数字, 直接比较数字, 不会出现例子中的问题.
6. Integer 做 > >= < <= 比较的时候, Integer会自动拆箱, 就是比较他们的数字值.
7. switch case 为选择语句, 匹配的时候不会用 equals(), 而是直接用 "==", 而在 switch case语句中, 语法层次面 case部分是不能写 Integer 对象的, 只能是普通数字, 如果是普通的数字就会将传入的Integer自动拆箱. 所以不会出现例子中的问题.
@Test public void testSwitchCase(){ Integer i = new Integer(3); switch (i) { case 2: System.out.println("1"); break; default: break; } }
case 2: 不能写为 case i: