`
xiaoyu1985ban
  • 浏览: 131625 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

Java迷题:等于,还是不等于?

    博客分类:
  • Java
阅读更多

等于还是不等于?

看来看下面的一段代码:

 

   代码片段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 <= 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文章版权属于作者,受法律保护。没有作者书面许可不得转载。若作者同意转载,必须以超链接形式标明文章原始出处和作者。

63
9
分享到:
评论
18 楼 et1009etoak 2012-02-01  
受教了。
17 楼 卖火柴的老特工 2012-02-01  
受教了。
valueof没有仔细看,原来用到缓存而且还有具体范围呢
16 楼 irshinning 2012-02-01  
用C++的方式来考虑也行,new出来的为指针在堆上,非new的为对象
15 楼 yoyo837 2012-02-01  
Integer缓存-127  到128啊
14 楼 lilinpu221 2012-02-01  
受教了,谢谢
13 楼 wangyj0898 2012-02-01  
受教了,讲得很详细啊。。。。
12 楼 OpenMind 2012-02-01  
1,片段一:
Integer a = new Integer(100); 
Integer b = 100;
前者对象构建在堆上(new),后者对象由编译器自动封装,所以二者是两个不同对象;

2, Integer a = 100; 
   Integer b = 100; 
   由编译器自动包装成对象,编译器自动包装也会使用缓存,且由于100<=127,使用的是IntegerCache,所以二者是同一个对象;

3, Integer a = 156; 
    Integer b = 156; 
同2,由编译器自动包装,但不使用缓存IntegerCache(因为156>127),所以是两个不同的对象;

4,  Integer a = Integer.valueOf(100); 
    Integer b = 100; 
valueOf会优先使用缓存,而编译器自动包装也会使用缓存,并且100<=127在缓存的范围内,所以二者是同一个对象。

解释完毕
11 楼 yzz9i 2012-02-01  
很精辟。
10 楼 yumpy 2012-02-01  
9 楼 河北潇潇 2012-02-01  
xiaoyu1985ban 写道
hejiang369 写道
楼主的说明错误
public static void main(String[] args) {
Integer a = 156;
Integer b = Integer.valueOf(156);
System.out.println(a == b);
}


public static void main(String[] args) {
Integer a = 100;
Integer b = Integer.valueOf(100);
System.out.println(a == b);
}
你使用这个两个打印试一下!


第一个是false,第二个是true。
能告知一下何处错误吗?谢谢

能解释的
8 楼 hlj79513 2012-01-31  
不错
7 楼 xiaoyu1985ban 2012-01-31  
hejiang369 写道
楼主的说明错误
public static void main(String[] args) {
Integer a = 156;
Integer b = Integer.valueOf(156);
System.out.println(a == b);
}


public static void main(String[] args) {
Integer a = 100;
Integer b = Integer.valueOf(100);
System.out.println(a == b);
}
你使用这个两个打印试一下!


第一个是false,第二个是true。
能告知一下何处错误吗?谢谢
6 楼 hejiang369 2012-01-31  
楼主的说明错误
public static void main(String[] args) {
Integer a = 156;
Integer b = Integer.valueOf(156);
System.out.println(a == b);
}


public static void main(String[] args) {
Integer a = 100;
Integer b = Integer.valueOf(100);
System.out.println(a == b);
}
你使用这个两个打印试一下!
5 楼 cfyme 2012-01-31  
学习了,学习了,谢谢
4 楼 PV_love 2012-01-31  
楼主说的很基础,也很重要,相信很多人还会经常犯错。
期待楼主的string,对象,等于不等于系列专题
3 楼 河北潇潇 2012-01-31  
2 楼 myspacedemen 2012-01-31  
1 楼 燈小嗨 2012-01-30  
通过此方法实现
public int intValue() {return value;}

返回的是自动装箱之前的int类型的值

相关推荐

    回复:Java迷题:等于,还是不等于?

    在阅读博客文章《Java迷题:等于,还是不等于?》时,你可能会发现更多关于这个话题的深入讨论,包括在特定场景下的最佳实践和陷阱。通过不断学习和实践,我们可以提升自己的编程技能,避免常见的错误,从而提高代码...

    《Java迷题解惑》PDF

    有意思的一本书,都是有点难度且又比较有意思的JAVA问题,比如表达式奇数性解惑、找零时刻、长整除、十六进制的趣数等等,特别是这本书的语言也很会激起我们的兴趣,先从实际生活中的故事说起,然后了解所需,最后用...

    java迷题

    Java中的String对象是不可变的,这意味着每次对String进行修改都会创建新的对象,这可能导致不必要的内存消耗。为避免这个问题,可以使用StringBuilder或StringBuffer类在需要多次修改字符串时。 3. null引用异常...

    java 解惑 挺多java方面的迷题

    为了解决这个问题,我们可以修改条件判断,使其比较`i % 2`是否不等于0,这样就能正确处理负数和正数的情况。此外,如果性能是关键因素,可以使用位操作符`&`代替取余操作符,以提高效率: ```java public static ...

    java试题精选(带有参考答案)

    Java是一种广泛使用的面向对象的编程语言,以其跨平台、高性能和丰富的类库而著名。这份“java试题精选”显然旨在帮助学习者检验和提升他们的Java编程技能。试题通常包括基础语法、面向对象概念、异常处理、集合框架...

    Java的终极迷题及答案

    这次Java SE的开发工具( JDK )包括了有利于开发applet和应用程序的Java运行环境( JRE环境)及命令行开发工具。 此更新版本的完整内部版本号是1.6.0_10 - b33。外部版本

    java基础入门教程

    香 港 则 在 今 年 4月 就 举 行 了 全 岛 的 Java杯 比 赛 ,在 计 算 机界掀 起 了 学 习 Java的热 潮 (尤 其 是 在 大 学 生 们 中 ,出 现 了 一 批 Java迷 )。 有 人 预 言 :Java将 是 网 络 上 的 "世 界 语 ...

    java期末考题&Dreamweaver试题

    Java和Dreamweaver是两种截然不同的技术,但它们都在IT行业中扮演着重要的角色。Java是一种广泛使用的编程语言,而Dreamweaver则是Adobe公司开发的一款专业网页设计与开发工具。 在"java期末考题"中,我们可以期待...

    计算机等级考试Java强化测试题及参考答案.docx

    6. **final关键字**:在Java中,`final`关键字用于声明常量,表示变量一旦赋值后就不能再改变。与C/C++中的`const`类似,但Java没有`const`关键字。 7. **boolean类型**:Java的布尔类型是基本数据类型之一,类型名...

    八数码算法java实现

    为了测试和验证这个Java实现,可能包含了一系列的测试用例,包括但不限于初始状态和目标状态已知的情况,以及一些具有挑战性的迷题。这有助于确保算法的正确性和效率。 总的来说,这个Java项目不仅展示了如何使用...

    Java-Algorithm:算法培训项目

    Java算法是计算机科学中的核心部分,它涉及到一系列用于解决复杂问题和优化计算过程的方法。在"Java-Algorithm:算法培训项目"中,我们主要探讨如何使用Java编程语言来实现各种经典的算法。这个项目旨在帮助开发者...

    aiyinsitan.rar_Java 8_aiyinsitan_java smoke_jmonkey_脑筋

    原题为: 1.有5栋5种颜色的房子 2.每一位房子的主人国籍都不同 ... 这道迷题出自1981年柏林的德国逻辑思考学院。 据说世界上只有2%的人能出答案。 就连大名鼎鼎的爱因斯坦也成为此题大伤脑筋。

    万得信息技术Java开发面经.pdf

    场景题:集群服务器宕机解决⽅案 8.MongoDB和redis区别,分别何时使⽤,MongoDB讲⼀下 9.完全平衡⼆叉树简述,红⿊树简述 10.mysql引擎底层 11.索引优化(什么时候⽤索引,什么时候不能⽤) 12.索引⼯作流程 13....

    数据结构与算法java版.rar

    本书提供了学习经典数据结构和算法的新...本书主要特点:在全书中使用Java 1.5的新特性,如泛型类型;使用行业标准统一建模语言来绘制类图和实例图;包含数百个习题、复习题和项目;本书给出了所有代码半均可在线获得。

    java变量作用域笔试题-arquillian-testrunner-spock:ArquillianSpockTestRunner

    java引发作用域笔试题Spock Arquillian 扩展 在容器中进行 BDD 测试! 它是什么? Arquillian 是在 JBoss.org 开发的测试框架,它使开发人员能够为在嵌入式或远程容器内执行的业务对象编写集成测试——选项包括 ...

    初级java笔试题-nand2tetris:nand2tetris.org课程的解决方案

    初级java笔试题nand2tetris.org 第 1 部分课程文件和答案 课程详情 Nand to Tetris 课程将带您进行自定进度的迷人发现之旅,您将一路从布尔代数和基本逻辑门到构建中央处理单元、存储系统和硬件平台,直至一台可以...

    leetcode第四题-rprater:代理

    第四题工程师和研究迷 我目前正在瑞尔森大学学习工程学,同时正在寻找我的第四次也是最后一次实习。 另一方面,我构建了很酷的 Python 项目并研究了混沌理论。 跟我来这里 我喜欢研究的东西 编码和辅助项目 机器学习...

    华为OD题解,共计112道题

    文章作者参考了MISAYAONE提供的题库,并提供了自己的Java解决方案,力求简洁高效,同时也对原有的错误进行了校对。尽管如此,由于没有全部上机实践,不能保证所有代码都能100%通过。 这些题目与LeetCode平台上的...

    12月全国计算机二级考试考前复习点破.docx

    1. 分析错误原因,是因为知识点掌握不牢,还是解题策略不当。 2. 复习相关知识点,确保理解和记忆。 3. 重新做题,直到能够独立正确解答。 4. 定期进行模拟测试,保持对考试环境的适应性。 在复习过程中,考生还应...

Global site tag (gtag.js) - Google Analytics