锁定老帖子 主题:在java 5中警惕”==“ 陷阱
该帖已经被评为新手帖
|
|
---|---|
作者 | 正文 |
发表时间:2011-02-08
在有些JVM中,Integer类型从-128到127的范围内会放回用一个对象,所以用”==“ 的时候,同样大小的Ingeter俩个对象会返回TRUE。而超过这个范围,就可能返回False了。 Integer i1 = 300; Integer i2 = 300; if (i1 == i2) System.out.println("i1 and i2 is equal"); else System.out.println("i1 and i2 is not equal ");
运行这段代码时,可能打印出的结果是 i1 and i2 is not equal 。因为JVM没有对这俩个对象自动解包,所以i1和i2是俩个不同的对象,所以它们不相同。又例如:
Integer i1 = 100; Integer i2 = 100; if (i1 == i2) System.out.println("i1 and i2 is equal"); else System.out.println("i1 and i2 is not equal ");
这时你运行代码则打印出 ”i1 and i2 is equal“ 这是为什么呢? 因为JVM对Int值从-128 到127范围的值会保存进行缓存保存,所以i1和i2实际上是同一个对象。
但这也不是绝对的,有一些JVM对Integer对象的保存会做些优化,所以会出现上面结果。所以我们要避免这种情况的发生,用equals()方法来比较Integer的大小。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-02-08
对象相等判定请用equals方法。
|
|
返回顶楼 | |
发表时间:2011-02-09
最后修改:2011-02-09
1.自动装箱拆箱不是JVM干的事情,是javac干的事情。
2.Integer缓存的数值下限是-128,上限默认值是127,但并非是固定的,在Sun JDK1.6之后可以由参数java.lang.Integer.IntegerCache.high设定。 3.没有遇到算术运算,javac是不会自动拆箱的,下面这段代码就会永远返回"i1 and i2 is equal" Integer i1 = 300; Integer i2 = 300; Integer i3 = 0; if (i1 == i2+i3) System.out.println("i1 and i2 is equal"); else System.out.println("i1 and i2 is not equal "); 4.下面这句话存在较大歧义 引用 这时你运行代码则打印出 ”i1 and i2 is equal“ 这是为什么呢? 因为JVM对Int值从-128 到127范围的值会保存进行缓存保存,所以i1和i2实际上是同一个对象。 不是JVM对Integer对象做了什么特殊处理,而只是Integer的valueOf()方法做了缓存处理而已,如果你把代码写成下面这样,肯定是走else分支。Integer i1 = new Integer(100); Integer i2 = new Integer(100); if (i1 == i2) System.out.println("i1 and i2 is equal"); else System.out.println("i1 and i2 is not equal "); 5.装箱后,equals()方法也并非就完全表达原始算术运算的意思,它不会进行type narrowing/widing,详将下面用例中变量g的两次比较。 public static void main(String[] args) { Integer a = 1; Integer b = 2; Integer c = 3; Integer d = 3; Integer e = 321; Integer f = 321; Long g = 3L; System.out.println(c == d); System.out.println(e == f); System.out.println(c == (a + b)); System.out.println(c.equals(a + b)); System.out.println(g == (a + b)); System.out.println(g.equals(a + b)); } |
|
返回顶楼 | |
发表时间:2011-02-09
楼上的总结不错~
IcyFenix 写道 2.Integer缓存的数值下限是-128,上限默认值是127,但并非是固定的,在Sun JDK1.6之后可以由参数java.lang.Integer.IntegerCache.high设定。
楼主有兴趣的话可以参考这里的正文和回复:[FYI] 关于Integer的自动缓存大小 我的观察是Sun的JDK是从6 update 14开始能配置该上限的。 IcyFenix 写道 3.没有遇到算术运算,javac是不会自动拆箱的,下面这段代码就会永远返回"i1 and i2 is equal"
Integer i1 = 300; Integer i2 = 300; Integer i3 = 0; if (i1 == i2+i3) System.out.println("i1 and i2 is equal"); else System.out.println("i1 and i2 is not equal "); 例子不错(挑刺:is -> are),不过讲解或许干涩了一点? 这里涉及好几处转换,首先是i2 + i3,由于有算术运算所以需要进行自动拆箱,于是i2 + i3这个表达式的静态类型是int(而不是Integer);接下来是==,右边的表达式类型是int了,那么就迫使左边生成自动拆箱的代码与之匹配。所以实际上变成了: if (i1.intValue() == i2.intValue() + i3.intValue()) 这是Java语言规范索要求的。自然,这样的程序执行的结果就总是走例子中的then而不是else分支了。 |
|
返回顶楼 | |
发表时间:2011-02-09
这是因为JAVA中 会封装-128 到127直接的数到缓存中,当赋值的数在这个区间内的时候,Integer会直接赋予缓存中的地址。
若赋值不在这个区间内的时候,Integer就会创建新对象,指向的地址也就不一样了。 所以一般 类型比较的时候,我们一般都用equals()去比较对象。 除非你用 int数据类型 才用 == |
|
返回顶楼 | |
发表时间:2011-02-09
结合这个看看Integer的源代码,受益匪浅
IcyFenix 写道 1.自动装箱拆箱不是JVM干的事情,是javac干的事情。
2.Integer缓存的数值下限是-128,上限默认值是127,但并非是固定的,在Sun JDK1.6之后可以由参数java.lang.Integer.IntegerCache.high设定。 3.没有遇到算术运算,javac是不会自动拆箱的,下面这段代码就会永远返回"i1 and i2 is equal" Integer i1 = 300; Integer i2 = 300; Integer i3 = 0; if (i1 == i2+i3) System.out.println("i1 and i2 is equal"); else System.out.println("i1 and i2 is not equal "); 4.下面这句话存在较大歧义 引用 这时你运行代码则打印出 ”i1 and i2 is equal“ 这是为什么呢? 因为JVM对Int值从-128 到127范围的值会保存进行缓存保存,所以i1和i2实际上是同一个对象。 不是JVM对Integer对象做了什么特殊处理,而只是Integer的valueOf()方法做了缓存处理而已,如果你把代码写成下面这样,肯定是走else分支。Integer i1 = new Integer(100); Integer i2 = new Integer(100); if (i1 == i2) System.out.println("i1 and i2 is equal"); else System.out.println("i1 and i2 is not equal "); 5.装箱后,equals()方法也并非就完全表达原始算术运算的意思,它不会进行type narrowing/widing,详将下面用例中变量g的两次比较。 public static void main(String[] args) { Integer a = 1; Integer b = 2; Integer c = 3; Integer d = 3; Integer e = 321; Integer f = 321; Long g = 3L; System.out.println(c == d); System.out.println(e == f); System.out.println(c == (a + b)); System.out.println(c.equals(a + b)); System.out.println(g == (a + b)); System.out.println(g.equals(a + b)); } |
|
返回顶楼 | |
发表时间:2011-02-09
其实总之一句话,不能把本来可以自己控制的主动权拱手让人,多写个equals多数情况下不会影响逻辑,也费不了多大的事,所以尽量还是别在比较算法上依赖自动拆箱装箱功能为妙。
|
|
返回顶楼 | |
发表时间:2011-02-09
用自动装箱就OK、这个是因为用了享元模式
|
|
返回顶楼 | |
发表时间:2011-02-09
wenrow 写道 这是因为JAVA中 会封装-128 到127直接的数到缓存中,当赋值的数在这个区间内的时候,Integer会直接赋予缓存中的地址。
若赋值不在这个区间内的时候,Integer就会创建新对象,指向的地址也就不一样了。 所以一般 类型比较的时候,我们一般都用equals()去比较对象。 除非你用 int数据类型 才用 == 说得好 |
|
返回顶楼 | |
发表时间:2011-02-09
能直接用基本类型的尽量直接用基本类型吧,对象的开销大。
一定要用对象的话,比较用equals();比较保险。 |
|
返回顶楼 | |