等于还是不等于?

看来看下面的一段代码:

 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);

Code 3

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

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

代码片段4

 public static void main(final String[] args) {
Integer a = Integer.valueOf(100);
Integer b = 100;
System.out.println(a == b);
}

Code 4

最后的结果,可能你已经猜到了,是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 <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}

看到这儿,上面的代码就很明确了:对于-128到127的数字,valueOf返回的是缓存中的对象。所以两次调用Integer.valueOf(100)返回的都是同一个对象。

我们再先看代码片段3:根据上面的分析,代码片段3实际上等价于以下代码:

 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)实现的,那么自动拆箱是如何实现的呢?

声明:

文章来自于ITeye,欢迎访问我的博客:xiaoyu1985ban.iteye.com

ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。若作者同意转载,必须以超链接形式标明文章原始出处和作者。

Java迷题:等于,还是不等于?的更多相关文章

  1. Java中文字符处理的四大迷题

    虽然计算机对英文字符的支持非常不错,我们也恨不得写的程序只会处理英文的数据,但是昨为中国人,无可避免地要处理一些中文字符.当很简单的一件事情,遇到了中文,一切就不同了!本文就会讲述实际生产环境中遇到的 ...

  2. 50道经典的JAVA编程题 (11-15)

    50道经典的JAVA编程题 (11-15),新年的第一天,继续啦...\(^o^)/~,这50道题都跨年了啊...哈哈 [程序11] TestTN.java 题目:有1.2.3.4个数字,能组成多少个 ...

  3. 50道经典的JAVA编程题 (6-10)

    50道经典的JAVA编程题 (6-10),今晚做了10道了,累死了...感觉难度不是很大,就是不知道是不是最好的实现方法啊!希望大神们能给指点哈... [程序6]GCDAndLCM.java 题目:输 ...

  4. 【原创】这道Java基础题真的有坑!我也没想到还有续集。

    前情回顾 自从我上次发了<这道Java基础题真的有坑!我求求你,认真思考后再回答.>这篇文章后.我通过这样的一个行文结构: 解析了小马哥出的这道题,让大家明白了这题的坑在哪里,这题背后隐藏 ...

  5. mysql的基本查询(等于,不等于,between...and...,)

    单个字段多个字段查询 查询员工姓名 *注:在SQL语句中不区分大小写:SQL语句以“:”分号结束 select ename from emp; 注:select询句后面跟的是字段名称,select是关 ...

  6. 50道经典的JAVA编程题(汇总)

    这是一次不可思议的编程历程.从2013年的最后一天开始做这份题,中间连续好几天的考试,包括java考试(今天考试的JAVA编程题),直到今天完成了.挺有成就感的...废话不多说了,来电实质性的吧. 全 ...

  7. 50道经典的JAVA编程题(46-50)

    50道经典的JAVA编程题(46-50),最后五道题了,这是一个美妙的过程,编程真的能让我忘掉一切投入其中,感觉很棒.今天下午考完微机原理了,大三上学期就这样度过了,这学期算是解放了,可是感觉我还是没 ...

  8. 50道经典的JAVA编程题(41-45)

    50道经典的JAVA编程题(41-45),苦逼的程序猿,晚上睡不着了编程吧~今天坚持做10道题!发现编程能是我快乐...O(∩_∩)O哈哈~能平静我烦乱的心,剩下5道题留到考试完了再做吧!该睡觉了.. ...

  9. 今天考试的JAVA编程题

    今天早上考了java, 题目感觉还不错, 共四道题,有一道定义类的没啥意思就没列出来. 这三道题目还是不错的,特别是第一道,大一上学期学linux的时候,那时还没学C语言呢,准确的来说,还不知道什么是 ...

随机推荐

  1. ubuntu 14.10 安装 zabbix

    在ubuntu 14.10 上部署 zabbix 2.x 基本软件包安装 既然是ubuntu系统,当然要用好apt-get神器. 参考教程 URL:http://blog.csdn.net/cloud ...

  2. [HDU 4419] Colourful Rectangle (扫描线 矩形面积并)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4419 题目大意:比矩形面积并多了颜色,问染成的每种颜色的面积. 矩形面积并的扫描线维护的是长度,这道题 ...

  3. 树状数组HDU1166

    http://acm.hdu.edu.cn/showproblem.php?pid=1166 #include<stdio.h> #include<string.h> ]; i ...

  4. SQL Server :Stored procedures存储过程初级篇

    对于SQL Server,我是个拿来主义.很多底层的原理并不了解,就直接模仿拿着来用了,到了报错的时候,才去找原因进而逐步深入底层.我想,是每一次的报错,逼着我一点点进步的吧. 近期由于项目的原因,我 ...

  5. Android开发-API指南-Android简介

    Introduction to Android 英文原文:http://developer.android.com/intl/zh-cn/guide/index.html 采集日期:2014-4-16 ...

  6. OpenStack-Mitaka 一键安装测试环境脚本

    说明:这个脚本是采用Bash Shell编写,这个版本还只能作为测试环境搭建使用. 此脚本原形的发起人是网友:WuYuLiang.这里有他的博客链接:   第一版的链接: http://blog.cs ...

  7. IOS9以上如何导入铃声并设置

    1.打开iTunes,点击左侧的“音乐” .2.在右侧的MP3等音乐列表中选中一个要制作铃声的名字 .3.在这个名字上点击鼠标右键选择“显示简介”,在弹出窗口中选择“选项”.4.在选项标签栏中设定开始 ...

  8. Android基础总结(9)——网络技术

    这里主要讲的是如何在手机端使用HTTP协议和服务器端进行网络交互,并对服务器返回的数据进行解析,这也是Android最常使用到的网络技术了. 1.WebView的用法 Android提供的WebVie ...

  9. .net框架版本说明

    .NET框架 1.0..NET框架 1.1..NET框架 2.0..NET框架 3.0..NET框架 3.5..NET框架 4.00 .netframework3.0Windows Presentat ...

  10. 快速搭建 Node.js 开发环境以及加速 npm

    如何快速搭建 node 开发环境 npm 超慢 github 无法打开的问题 于是我觉得应该写一篇文章解答所有这些起步问题,让新同学也能顺顺利利入门. 快速搭建 Node.js 开发环境 如果你想长期 ...