2009-07-18 42 views
8

考虑以下代码:不一致的行为

class test { 
    public static void main(String[] args) { 
     test inst_test = new test(); 
     int i1 = 2000; 
     int i2 = 2000; 
     int i3 = 2; 
     int i4 = 2; 
     Integer Ithree = new Integer(2); // 1 
     Integer Ifour = new Integer(2); // 2 
     System.out.println(Ithree == Ifour); 
     inst_test.method(i3 , i4); 
     inst_test.method(i1 , i2); 
    } 
    public void method(Integer i , Integer eye) { 
     System.out.println(i == eye); 
    } 
} 

它打印:

false 
true 
false 

我知道,第一false,==操作符只检查两个引用是否正在使用的相同对象,在这种情况下不是。

以下truefalse让我挠了挠头。 Java为什么会考虑i3i4等于i1i2不同?两者都被封装到整数,不应该评价为false?这种不一致是否存在实际原因?

+2

我相信FindBugs会告诉你你的错误。 – 2009-07-18 23:18:43

回答

15

自动装箱原语为对象(如您的通话method用于使用小值的缓存从Java Language Specification section 5.1.7

如果被装箱值p是真实的, 假,字节,炭在\ u0000的范围 到\ u007f,或-128和127之间的int或短 号码,然后让 r1和r2是p中的任意两个 装箱转换的结果。它始终是 的情况是R1 == r2。

紧随其后的规范的讨论部分也很有趣。值得注意的是一个JVM可以缓存值,如果它想 - 你不能肯定这样做的结果:

Integer i1 = 129; 
Integer i2 = 129; 
boolean b = (i1 == i2); 
2

这是因为拳击使整数低于某个值(我认为128)是指一些预构造的对象,以及更高的值到新的对象。

7

当自动装箱时,缓存-128和127之间的整数,并返回相同的包装对象。与\ u0000和\ u007F之间的布尔值和字符值相同。

这就是您大部分时间得到的结果,但它取决于JVM实现。

+3

我曾经认为它也是JVM依赖的,但它实际上是在规范中。 – 2009-07-18 22:59:05

+2

(或者说,它是为这些值指定的,但不适用于其他值。) – 2009-07-18 23:00:53

0

我猜测包装会尽量减少整数对象的数量,并只创建一个代表2的对象,节省内存。

只记得不要在对象上使用==你永远不会知道发生了什么。

+0

是的,正如几个人所说的,不要使用==,除非寻求具有“知道发生了什么”支持的特定效果,并且一般使用: Boolean booLean = Boolean.valueOf(i.intValue()== eye.intValue()); System.out.println(booLean.toString()); – 2009-09-30 23:05:40

0

Integer类包含一些常用的实例的高速缓存。值的范围一般从JVM变化到JVM(有时也可配置),但一般相关的代码是一样的东西:

public static Integer valueOf(int i) { 
    if(i >= -128 && i <= IntegerCache.high) 
     return IntegerCache.cache[i + 128]; 
    else 
     return new Integer(i); 
} 

(代码太阳JDK 1.6)

这就像串实习,因为它既节省了内存,又允许使用引用(例如,==代替等于

1

自动装箱使用Integer.valueOf(ⅰ),不是新的整数(i)中,以构建Integer类的对象。

正如其他人所说的,valueOf()使用缓存,主要是为了空间效率。

不要在引用类型上使用==,它几乎总是一个错误。

0

自动装箱使用一些缓存机制。通常你不应该依靠==,总是用equals来检查平等。