`
zhanghong
  • 浏览: 90741 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

在java 5中警惕”==“ 陷阱

    博客分类:
  • Java
阅读更多

在有些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的大小。

分享到:
评论
13 楼 pml346680914 2011-06-09  
虽然没碰到过、不过给我上了一课、以后遇见对象就equals方法比较稳妥
12 楼 jorneyR 2011-02-09  
这都是自己给自己找麻烦
11 楼 TonyBug 2011-02-09  
你等于声明了两个对象,在内存中会给你开辟两个地址,分别保存,要想比较,就用equals
10 楼 eric_shi 2011-02-09  
java 需要深入了解
9 楼 redstarofsleep 2011-02-09  
能直接用基本类型的尽量直接用基本类型吧,对象的开销大。

一定要用对象的话,比较用equals();比较保险。
8 楼 xiaohui886688 2011-02-09  
wenrow 写道
这是因为JAVA中 会封装-128 到127直接的数到缓存中,当赋值的数在这个区间内的时候,Integer会直接赋予缓存中的地址。

若赋值不在这个区间内的时候,Integer就会创建新对象,指向的地址也就不一样了。

所以一般 类型比较的时候,我们一般都用equals()去比较对象。
除非你用 int数据类型 才用 ==


说得好
7 楼 念不动 2011-02-09  
用自动装箱就OK、这个是因为用了享元模式
6 楼 abettor 2011-02-09  
其实总之一句话,不能把本来可以自己控制的主动权拱手让人,多写个equals多数情况下不会影响逻辑,也费不了多大的事,所以尽量还是别在比较算法上依赖自动拆箱装箱功能为妙。
5 楼 xieshaohu 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));
}

4 楼 wenrow 2011-02-09  
这是因为JAVA中 会封装-128 到127直接的数到缓存中,当赋值的数在这个区间内的时候,Integer会直接赋予缓存中的地址。

若赋值不在这个区间内的时候,Integer就会创建新对象,指向的地址也就不一样了。

所以一般 类型比较的时候,我们一般都用equals()去比较对象。
除非你用 int数据类型 才用 ==
3 楼 RednaxelaFX 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分支了。
2 楼 IcyFenix 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));
}
1 楼 Agrael 2011-02-08  
对象相等判定请用equals方法。

相关推荐

Global site tag (gtag.js) - Google Analytics