A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 刘云龙 中级黑马   /  2013-3-17 19:43  /  3388 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

/*
Integer类型重写了equals方法,为什么结果是:
i1 equals i2 :true
i1 == i2 :false
i3 equals i4 :true
i3 == i4 :true//这里应该是false啊?
*/

public class IntegerTest
        {
        public static void main(String[] args)
                {
                // 定义两个Integer类型的数据
                // true,false
                Integer i1 = 128;//new Integer(128);
                Integer i2 = 128;//new Integer(128);
                // Integer类型重写了equals方法,比较的是值
                System.out.println("i1 equals i2 :" + i1.equals(i2));
                System.out.println("i1 == i2 :" + (i1 == i2));

                // true,true
                Integer i3 = 127;
                Integer i4 = 127;
                System.out.println("i3 equals i4 :" + i3.equals(i4));
                System.out.println("i3 == i4 :" + (i3 == i4));
        }
}

点评

再次提醒: 如果问题未解决,请继续追问回复者,如果问题已经解决,请将分类改为“已解决”,否则将扣除技术分,谢谢  发表于 2013-3-18 12:09
如果问题未解决,请继续追问回复者,如果问题已经解决,请将分类改为“已解决”,谢谢  发表于 2013-3-18 06:16

评分

参与人数 1技术分 +1 收起 理由
贾文泽 + 1

查看全部评分

7 个回复

倒序浏览
哥们是这样的:
首先你要知道数据的最小存储单位是字节!
所以JAVA程序的工程师们在设计这门语言的时候就考虑到了节约内存资源以及增加效率,不然每次都要创建对象就会很麻烦!

结论是:包装类里面直接赋值的时候,127及以下的值会在一个常量池里面,直接从常量池获取,不需要重新创建!

评分

参与人数 1技术分 +1 收起 理由
猫腻 + 1

查看全部评分

回复 使用道具 举报
首先要介绍一个设计模式叫享元模式,也就是“对于基本类型的整数,要装箱成Integer,如果整数在-128-127之间,产生之后会被缓存起来以便多次调用”
关于享元模式:如果很多小的对象它们有很多相同的东西,那就可以把它们变成一个对象,那些不同的属性变成方法的参数,称之为外部状态,相同的属性称之为内部状态,这在张孝祥老师java加强的视频里有介绍,就是装箱拆箱那一部分
回复 使用道具 举报
内存中的方法区中有个常量池,为了节省资源,避免每次都要重新创建对象,而数据的最小存储单位是字节,在常量池中有26个英文字母及127以下的数,为了方便使用,直接赋值的话,会从常量池中直接获取该值,以减少因创建对象而造成的内存使用浪费.所以看下面的注释
public class IntegerTest
        {
        public static void main(String[] args)
                {
                // 定义两个Integer类型的数据
                // true,false
                Integer i1 = 128;//new Integer(128);
                Integer i2 = 128;//new Integer(128);
                // Integer类型重写了equals方法,比较的是值
                System.out.println("i1 equals i2 :" + i1.equals(i2));
                System.out.println("i1 == i2 :" + (i1 == i2));

                // true,true
                Integer i3 = 127;
                Integer i4 = 127;
                System.out.println("i3 equals i4 :" + i3.equals(i4));
                System.out.println("i3 == i4 :" + (i3 == i4));//这里用==比较的是地址值,都是从常量池中获取的127,所以地址值相同,输出true
        }
}

评分

参与人数 1技术分 +1 收起 理由
猫腻 + 1

查看全部评分

回复 使用道具 举报
本帖最后由 吴上波 于 2013-3-17 20:37 编辑

这个问题比较容易混淆
首先 “== ” 比较基本数据类型时,比较的是其值,比较引用变量时,比较的是其引用地址内存.这点楼主肯定清楚的~~

Integer类型重写了equals方法,为什么结果是:
i1 equals i2 :true                         ----->
i1 == i2 :false                             ----->i1不等于i2:是因为i1和i2指向了堆内存中的两个不同的对象,他们的内存地址是不同的,所以返回false
i3 equals i4 :true                         ----->
i3 == i4 :true//这里应该是false啊? ----->i3等于i4  :是因为小于等于127的整数实际在内存中已经存在了,i3和i4都指向了内存中的同一个127,而不是分别创建两个对象,所以返回true

PS:出于性能的考虑,JVM将-128到127的小整数在内存中做了备份,这样可以避免频繁创建删除操作影响性能
系统把-128~127之间的整数自动装箱成Integer实例,并放入一个名为cache的数组缓存起来
如果把一个-128~127之间的整数自动装箱成一个Integer实例,实际上就是直接指向数组元素,而不会创建新的对象~~~!
但每次把一个不在-128~127的范围内整数自动装箱成Integer实例时,系统需重新创建一个Integer对象

评分

参与人数 1技术分 +1 收起 理由
贾文泽 + 1

查看全部评分

回复 使用道具 举报
对于Integer类,重写了equals方法,equals比较的是两个包装类中数字的内容是否相同。
i1.equals(i2)为true,因为都是128
i3.equals(i4)为true,也是同样的道理,
对于==,比较的是地址值是否相同,在Integer包装类中,如果这个数字没有超过一个字节
也就是从-128~127之间的数字,每次装箱的时候会先判断之前是否有该数字,
比如执行Integer i3 = 127;进行了装箱,判断出数字在一个字节内,实际上是这样操作的
Integer i3 = new Integer(127);
然后执行Integer i4 = 127;时,这个时候,它会先判断是否在-128~127之间,是,然后在判断是否
存在内容为127这个包装类,因为前面已经存在了,所以进行自动包装的时候就不在重新创建一个新的
对象,把原来的那个对象的地址赋值给i4,所以i3和i4都引用了同一个地址,所以i3==i4为true。
对于超过一个字节范围内的数字就要每次重新创建对象,所以i1==i2为false,因为他们不会指向同一个对象。

评分

参与人数 1技术分 +1 收起 理由
贾文泽 + 1

查看全部评分

回复 使用道具 举报
Integer i3 = 127;
Integer i4 = 127;
                System.out.println("i3 == i4 :" + (i3 == i4));
虽然 i3被包装成了Integer类型,但127是在byte范围内的。byte取值范围-128~127
而byte范围内的数据直接赋值是从bytei常量池里面获取的。
也就是说 i 3 和 i 4都同时指向了常量池,所以他们的地址值是true

评分

参与人数 1技术分 +1 收起 理由
贾文泽 + 1

查看全部评分

回复 使用道具 举报
谢谢各位的解答
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马