表面上看来这只是一些基础的问题,当真正的了解了以后你就会发现:啊,原来是这么一回事!下文是几道Java谜题,不仔细分析就会犯错哦。

AD:


等于还是不等于?

看来看下面的一段代码:

代码片段1

public static void main(final String[] args) { 

Integer a = new Integer(100); 

Integer b = 100; 

System.out.println(a == b); 

}


这段代码的输出是什么?相信很多人都会很容易的猜到:false,因为a、b两个对象的地址不同,用“==”比较时是false。恭喜你,答对了。

再看下面的一段代码:

代码片段2

public static void main(final String[] args) { 

Integer a = 100; 

Integer b = 100; 

System.out.println(a == b); 

}


你可能会回答,这没什么不一样啊,所以还是false。很遗憾,如果你执行上面的一段代码,结果是true。

上面的代码可能让你有些意外,那好吧,再看看下面的这段代码:

代码片段3

public static void main(final String[] args) { 

Integer a = 156; 

Integer b = 156; 

System.out.println(a == b); 

}


结果是true吗?很遗憾,如果你执行上面的一段代码,结果是false。

感到吃惊吗?那最后再看下面的一段代码:

代码片段4

public static void main(final String[] args) { 

Integer a = Integer.valueOf(100); 

Integer b = 100; 

System.out.println(a == b); 

}


最后的结果,可能你已经猜到了,是true。

为什么会这样?

现在我们分析一下上面的代码。可以很容易的看出,这一系列代码的最终目的都是用“==”对两个对象进行比较。Java中,如果用“==”比较两个对象结果为true,说明这两个对象实际上是同一个对象,false说明是两个对象。

现在,我们来看看为什么会出现上面的现象。

我们先看代码片段4:最后的运行结果是true,说明a、b两个对象实际上是同一个对象。但是a对象是通过调用Integer的valueOf方法创建的,而b对象是通过自动装箱创建出来的,怎么会是同一个对象呢?难道问题在字节码那里,毕竟Java程序是依靠虚拟器运行字节码来实现的。

通过jdk中自带的工具javap,解析字节码,核心的部分摘取如下:

0: bipush 100 

2: invokestatic #16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 

5: astore_1 

6: bipush 100 

8: invokestatic #16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

代码中我们只调用了一次Integer.valueOf方法,但是字节码中出现了两次对Integer.valueOf方法的调用。那么另一次是哪里呢?只可能在自动装箱时调用的。因此这段代码实际上等价于:

public static void main(final String[] args) { 

Integer a = Integer.valueOf(100); 

Integer b = Integer.valueOf(100); 

System.out.println(a == b); 

}


现在问题就简单了:看jdk源代码,查看valueOf方法的具体实现:

public static Integer valueOf(int i) { 

final int offset = 128; 

if (i >= -128 && i