为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

java谜题等于还是不等于

2012-02-11 11页 doc 1MB 37阅读

用户头像

is_052754

暂无简介

举报
java谜题等于还是不等于Java 谜题等于还是不等于 看来看下面的一段代码: 代码片段1 Java代码 public static void main(final String[] args) { Integer a = new Integer(100); Integer b = 100; System.out.println(a == b); } 这段代码的输出是什么?相信很多人都会很容易的猜到: false,因为a、b两个对象的地址不同,用“==”比较时是false...
java谜题等于还是不等于
Java 谜题等于还是不等于 看来看下面的一段代码: 代码片段1 Java代码 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 Java代码 public static void main(final String[] args) { Integer a = 100; Integer b = 100; System.out.println(a == b); } 你可能会回答,这没什么不一样啊,所以还是false。很遗憾,如果你执行上面的一段代码,结果是true。 上面的代码可能让你有些意外,那好吧,再看看下面的这段代码: 代码片段3 Java代码 public static void main(final String[] args) { Integer a = 156; Integer b = 156; System.out.println(a == b); } 结果是true吗?很遗憾,如果你执行上面的一段代码,结果是false。 感到吃惊吗?那最后再看下面的一段代码: 代码片段4 Java代码 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,解析字节码,核心的部分摘取如下: Java代码 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方法的调用。那么另一次是哪里呢?只可能在自动装箱时调用的。因此这段代码实际上等价于: Java代码 public static void main(final String[] args) { Integer a = Integer.valueOf(100); Integer b = Integer.valueOf(100); System.out.println(a == b); } 现在问题就简单了:看jdk源代码,查看valueOf方法的具体实现: Java代码 public static Integer valueOf(int i) { final int offset = 128; if (i >= -128 && i <= 127) { // must cache return IntegerCache.cache[i + offset]; } return new Integer(i); } 看到这儿,上面的代码就很明确了:对于-128到127的数字,valueOf返回的是缓存中的对象。所以两次调用Integer.valueOf(100)返回的都是同一个对象。 我们再先看代码片段3:根据上面的分析,代码片段3实际上等价于以下代码: Java代码 public static void main(final String[] args) { Integer a = Integer.valueOf(156); Integer b = Integer.valueOf(156); System.out.println(a == b); } 由于156不在-128到127范围内,所以两个对象都是通过new Integer()的方式创建的,所以最后结果为false。 片段1和片段2就不做具体分析了,相信读者可以自行分析。 最后,请大家思考一下问题:通过上面的分析,了解到整数的自动装箱是通过Integer.valueOf(int number)实现的,那么自动拆箱是如何实现的呢? 通过此方法实现 public int intValue() {return value;} 返回的是自动装箱之前的int类型的值 对于基本类型,以及基本类型的比较,我一直都是用“==”来进行比较的。一直没注意这个问题,今天遇到了吓一大跳。庆幸过去的程序中用“==”没出现问题。把源码拖出来看了一下,明白了,解释如下: 平常我们使用Integer a = xxx;的时候,Integer类实际上是调用的是public static Integer valueOf(int i)方法。这个方法是这样的。 [java]view plain HYPERLINK "http://blog.csdn.net/my11120/article/details/5777545#"copy public static Integer valueOf(int i) { final int offset = 128; if (i >= -128 && i <= 127) { // must cache return IntegerCache.cache[i + offset]; } return new Integer(i); } 从上面代码可以看出,当进行赋值操作时,Java将这个值分为两个区间来处理,即: i 属于[-128, 127]的时,返回IntegerCache.cache[i + offset]; i 属于上面范围以外时,返回new Integer(i)。 上面实例程序中,赋值超出[-128, 127]返回,所以返回为new Integer(1000),而“==”比较是比较内存地址,那么返回值肯定为FALSE。 至此上面陈述的诡异问题就解开了。 但是Java为什么要这样分区间处理呢,这不是使劲儿把我们往误区里勾引吗?为此我测试了这样一个程序:赋值在[-128, 127]之间时。 [java]view plain HYPERLINK "http://blog.csdn.net/my11120/article/details/5777545#"copy public class Test { public static void main(String[] args) { Integer a = 10; Integer b = 10; System.out.println("a==b : " + (a == b)); System.out.println("a.equals(b) : " + a.equals(b)); } } 这段代码的输出结果是这样的: [java]view plain HYPERLINK "http://blog.csdn.net/my11120/article/details/5777545#"copy a==b : true a.equals(b) : true 为什么出现这种现象呢?这就要问IntegerCache.cache[i + offset]了,跟踪进去代码如下: [java]view plain HYPERLINK "http://blog.csdn.net/my11120/article/details/5777545#"copy static final Integer cache[] = new Integer[-(-128) + 127 + 1]; static { for(int i = 0; i < cache.length; i++) cache[i] = new Integer(i - 128); } 也就是说,当赋值在[-128, 127]区间时,Java是从同一个数据中取出同一个对象,即内存地址一样,所以“==”操作返回TRUE; 那么猜测Java这样做的目的,可能[-128, 127]区间比较常用,这个区间内的Integer对象也作为静态变量初始化完成,这样直接返回对象可以提高效率。 为了防止不小心掉入这样的陷阱,对于基本类型的比较,用“==”;而对于基本类型的封装类型和其他对象,应该调用public boolean equals(Object obj)方法(复杂对象需要自己实现equals方法)。 其实不仅仅Integer有这样的问题 Long也是这么处理的
/
本文档为【java谜题等于还是不等于】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索