黑马程序员技术交流社区

标题: 大神, 帮忙看看咯 [打印本页]

作者: flydream    时间: 2016-8-6 22:43
标题: 大神, 帮忙看看咯
               Integer i=new Integer(3);
                Integer j=new Integer(3);
                System.out.println(i==j);
                System.out.println(i.equals(j));
               
                Integer i1=3;
                Integer j1=3;
                System.out.println(i1==j1);
                System.out.println(i1.equals(j1));
这又啥区别啊,真实醉了,


作者: absvir    时间: 2016-8-6 22:43
这是包装类自动装箱拆箱的内容。正常来说,Integer i = new Integer(3);的内部流程应该是i存储着3所在的地址,直接使用i的话,取出的应该是3的地址值,而不是3本身。Integer i=3;同理,它的正常作用应该是就是把3赋值给i。但是(最重要的就是这个但是),Integer等基本数据包装类,有自动装箱和自动拆箱功能,当你使用Integer i=3;时它会自动完成Integer i=new Integer(3);的流程与功能,这是自动装箱。而当你在完成i的初始化要使用i的时候,比如System.out.println(i);正常来讲,输出i的地址值,而不是3。但Java会自动通过i存储的地址值,直接找到3。这个过程叫自动拆箱。而i==j与i.equals(j),i==j比较的就是i于j的地址值,而i.equals(j)比较的是i于j地址值所代表的内容。你发的代码踩进了一个坑,所以看不出差别的。因为实际使用中,小数字使用率极高,所以为了节省内存,所有取值范围在(-128~127)之间的数字都会使用同一个值。即你以上的代码中,i j i1 j1四个变量实际上都因为Java的内部设计而指向同一个3。想看出==和equals的区别,不要使用(-128~127,这也是byte类型的取值范围)这个范围之内的数。如有帮助,忘请采纳!
作者: flydream    时间: 2016-8-6 22:46
一个是用的引用性的,一个是常量池类型的
作者: flydream    时间: 2016-8-6 22:47
一个是引用类型的,一个是常量池,应该是这样的
作者: 樱释空    时间: 2016-8-6 23:48
第一个是创建对象的,存在堆里面,第二个只是在常量池的.integer:==是比较地址值,equals是比较内容看其是否相等!
作者: 丁丁丁    时间: 2016-8-7 09:18

第一个用的引用类型的,第二个是常量池类型的,好好回顾一下
作者: 阿卜    时间: 2016-8-7 11:33
首先,Integer类重写了equals()方法,作用为对比数据的值,所以两个都是true;
i和j是2个不同的对象(都是new出来的新的),所以i和j被赋予的地址值不一样,所以i == j为false;
i1和j1并不是new的对象,他们的地址值都是指向常量池的3这个数据,所以i1 == j1 为true。

另外注意超过byte取值范围的i == j为false
Integer i = 128;
Integer j = 128;
i == j   false

作者: it老菜鸟    时间: 2016-8-7 16:59
上面  i     new了Interger 所以在堆内存中创建了一个对象,J同样也创建了一个对象,表明
作者: it老菜鸟    时间: 2016-8-7 17:07
上面      i     new了Interger 所以在堆内存中创建了一个对象,
            J同样也创建了一个对象,表明地址 值不一样。
”==”号表明的是判断地址值是否一样     此处明显两个对象互不干扰  结果为为false ,
equals则判断的是内容一样就为true
下面
则是 i1 和 j1 分别指向常量池里的同一个数字
则==号判断地址值一样就返回结果true
eqauls 判断内容一样 返回结果为true
另外常量池里的数字是不能超过-128~127的
作者: liusonglin    时间: 2016-8-8 00:11
本帖最后由 liusonglin 于 2016-8-8 01:29 编辑

        Integer i1 = 3;
        Integer j1 = 3;
JDK5的新特性 -- 自动装箱,以上代码等价于(通过反编译工具可以看到):
        Integer i1 = Integer.valueOf(3);
        Integer j2 = Integer.valueOf(3);
查看原码:
        // 这个是valueOf()方法的原码
        public static Integer valueOf(int i) {
                assert IntegerCache.high >= 127;
                if (i >= IntegerCache.low && i <= IntegerCache.high)
                return IntegerCache.cache[i + (-IntegerCache.low)];
                return new Integer(i);
        }

        // 这个是Integer类中的内部类原码
        private static class IntegerCache {
                static final int low = -128;
                static final int high;
                static final Integer cache[];

                 static {
                        // high value may be configured by property
                         int h = 127;
                        String integerCacheHighPropValue =
                        sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
                        if (integerCacheHighPropValue != null) {
                                 int i = parseInt(integerCacheHighPropValue);
                                 i = Math.max(i, 127);
                                 // Maximum array size is Integer.MAX_VALUE
                                 h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                         }
                        high = h;

                        cache = new Integer[(high - low) + 1];
                         int j = low;
                         for(int k = 0; k < cache.length; k++)
                                 cache[k] = new Integer(j++);
                 }

                 private IntegerCache() {}
         }
        
        从红色标记可以得知:IntegerCache.low = -128,IntegerCache.high = 127
        针对 -128 到 127 之间的数据做了一个数据缓冲池,如果数据是该范围内的,每次并不创建新的空间,所以 i1 和 j1 的地址值相同。
作者: liusonglin    时间: 2016-8-8 00:12
结果为:
false
true
true
true
作者: 王高威    时间: 2016-8-9 17:20
第一个代码创建的是引用数据类型,
第一个输出语句比较的是地址值,两个对象的地址值肯定是不同的,故而为false
第二个输出语句比较的是内容,两者都是3,故而为true

第二个代码是直接赋值为3,
第一个输出语句比较的是值,故而为true
第二个输出语句比较的是内容,也为true
作者: 骚动的石头    时间: 2016-8-9 22:26
本帖最后由 骚动的石头 于 2016-8-9 22:32 编辑

结果为 false true true true  
你再来看这段代码.和你第二段代码类似,结果却不同
          Integer i2=200;
          Integer j2=200;
         System.out.println(i2==j2);
         System.out.println(i2.equals(j2));结果为false true
equals 就不说了   说说 ==吧
Integer i2=200;     Integer j2=200;   这两个是有包含有自动装箱的,其中用了Integer的valueOf方法
当数值是 -128 - 127 时候 Integer是有一个池来放这些数字的  所以i1与i2地址值是一样的.  
但是超过这个范围,就要在堆内存中新创建空间了,所以地址不一样




作者: 刘安    时间: 2016-8-9 22:30
哦哦 巧了这个我们今天刚学如果你把i1=128  j1=128  然后i1==j1就是false了    Integer i1=new Integer(x);//手动装箱           Integer i2=100;//自动装箱这是jdk1.5的新特性~~建议你多看看笔记~~~考试可能要考
作者: double_x    时间: 2016-8-10 20:27
上面的是引用数据类型  下面的是常量  基本数据
作者: 魏斌    时间: 2016-8-11 11:27
运行结果:
false
true
true
true
原因解析:
== 判断的是地址值是否相等,即是否同一个对象
Integer 中 的equals方法 是判断 Integer 值是否相等
1、第一个由于是new 对象,两个语句创建两个对象分配两个地址值;
      ==判断地址值,由于地址值不一样则返回false;
      equals判断Integer 值是否相等 ,3 等于3,故返回true;
2、第二个属于装箱,由于右边属于常量,在编译时,编译器会将常量在内存方法区中的常量池中进行常量对象创建,为了避免重复创建常量,编译器有常量优化机制,在进行常量创建时,首先进行检索,看常量池是否存在相同常量,如果存在则直接引用,不再进行新建。
      故第一次创建常量对象后,第二次直接引用该常量。即两者引用指向相同对象。
      ==判断地址值,由于指向同一对象,故地址值相等,返回true;
        equals判断Integer 值是否,同一对象,故返回true。
----------------------------------------------------
Integer 中 equals 的源代码
public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

-----------------------------------------------------


作者: double_x    时间: 2016-8-12 22:30
一个是对象 引用类型 一个是常量
作者: wzplol    时间: 2016-8-14 23:40
一个引用类型,一个常量类型,一个在堆里进行,一个在栈里进行
作者: wq1194165366    时间: 2016-8-15 23:24
这个是自动装箱和自动拆箱的操作,]
new的话就是在堆区新建了一个对象,所以地址值就不一样
但是在常量池中就会有一个匹配一个整型包装类
所以呢,这是有区别的,
作者: 汐城西下    时间: 2016-8-17 22:39
new Integer,是创建两个对象,Integer I=97对象是从常量池里面拿的
作者: Fightingdd    时间: 2016-8-20 17:35
上边那个new出来的对象会放到堆中,每new 一个就会在堆中开辟一个空间,引用数据类型==比较的是地址值,所以第一个==输出是false,equals比较的是内容输出true
第二个是方法是放到常量池中,integer ==比较地址值 equals 比较是内容

作者: zhangliuxian    时间: 2016-8-20 23:11
基本类型==和equals比较的都是值,引用类型==比较的是地址,equals比较的是值
作者: li274819748    时间: 2016-8-21 14:03
==号是比较两个地址是否相同,而equal是用来比较数值是否相等的。
Integer i=new Integer(3);     
Integer j=new Integer(3);        //这等于在堆内存中创建了两个对象,所有地址是不同的,而内容是一样的
System.out.println(i==j);          //结果为false
System.out.println(i.equals(j));     //结果为true

Integer i1=3;
Integer j1=3;        //地址相同,内容也相同
System.out.println(i1==j1);       //结果为true
System.out.println(i1.equals(j1));   //结果为true




作者: ObjectGitHub    时间: 2016-8-21 21:11
第一个是new出来的,两个量的地址值是不一样的。第二个是直接指向同一个地址。不知道说对不对。
作者: wangyuji    时间: 2016-8-23 15:51
第一种:i和j是分别开辟了两块内存地址来存储这两个值,所以 System.out.println(i==j);计算时为false(地址不同)
第二种:i1在内存空间开辟了一块地址存储3,存储j1时会先去已创建的对象里寻找是否有相同的值,有的话就使用地址,由于j1的值和i1的值是相同的,所以j1是直接引用i1的值,所以System.out.println(i1==j1);计算出来的值为true

“= =”比较两个变量本身的值,即两个对象在内存中的首地址。“equals()”比较字符串中所包含的内容是否相同
作者: tbh    时间: 2016-8-23 20:16
                Integer i=new Integer(3);   //这句话在堆内存中创建了一个空间,并存储了 3
                Integer j=new Integer(3);  //同上
                System.out.println(i==j);   // == 号直接判断地址值,因为是开辟了两个空间,所以两个地址值不同,返回false
                System.out.println(i.equals(j));  //  equals 判断值,所以返回true
               
                Integer i1=3;         // 在这个语句执行的时候,会先判断常量池中有没有这个数字,有的话会记录常量池中的地址,没有的话会放到常量池中并记录地                                               //址值
                Integer j1=3;         //  同上
                System.out.println(i1==j1);    // == 判断地址值,由于两个变量中存储的是常量池中的同一个地址,所以返回true
                System.out.println(i1.equals(j1));  // equals 判断内容,两个值相等,所以返回 true
作者: 小超超    时间: 2016-8-25 11:28
Integer i=new Integer(3);        //在堆内存中创建一个对象1,然后将该对象的地址赋值给i
            Integer j=new Integer(3);        //在堆内存中创建一个对象2,注意和上一个对象不是一个,然后将该对象的地址赋值给j
            System.out.println(i==j);        //i中存储的是对象1的地址,j中存储的是对象2的地址,== 是比较两个对象的地址,所有输出是false
            System.out.println(i.equals(j));        //.equals()比较的是对象中的内容,所以结果是true
               
            Integer i1=3;        //在方法区中的常量区为“3”分配一个空间,将该空间的地址赋值给i1
            Integer j1=3;        //程序发现常量区中有“3”,所以就直接将“3”的内存地址赋值给j1
            System.out.println(i1==j1);        //==比较的是地址,所以结果是true
            System.out.println(i1.equals(j1));        //.equals()比较的是内容,所以结果还是是true
作者: 铜雀台    时间: 2016-8-30 00:26
没分啊,哈哈哈
作者: 梦想的小草    时间: 2016-8-31 22:44
本帖最后由 梦想的小草 于 2016-8-31 22:48 编辑

前面两个是new出来的值,存在于堆中,栈中的引用对象指向堆内存.后两个存在于方法区的常量池中,指向的是方法区,第一个比较的地址,输出false,第二个默认比较的也是地址,但是比较的如果是引用类型时,比较的是值,所有返回true;后两个都是指向的常量池的同一对象,所有地址和值都相等都是true;
如果不理解,你只要记得new出来的东西==都返回false,如果是引用类型equals则true,基本数据类型还是false;如果存在于常量池的东西,==与equals都是true;

作者: 噜噜吧    时间: 2016-9-1 11:58
==操作比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量在堆中存储的地址是否相同,即栈中的内容是否相同。

    equals操作表示的两个变量是否是对同一个对象的引用,即堆中的内容是否相同。

    ==比较的是2个对象的地址,而equals比较的是2个对象的内容。
作者: Android一米阳光    时间: 2016-9-1 21:46
首先,==是比较地址值得,上面在堆中new了两个对象,所以地址值不同,而Integer是重写过equals()方法的,比较的是字面值,如果一模一样的就相等;下面的两个是跟常量池有关,常量池自带有个byte类型范围的整形,就是你赋值的数不超过
-128-127,在常量池都有,因为是常量,地址一致,所以相等;当你输入两个128的话,就会出现false
作者: WHH123    时间: 2016-9-1 22:15
integer里底层有一个cache缓存数组,-128到127之间的数据,你不用new的话,他是取的同一个地址,比较地址时是true,而用new的话会开辟新的堆内存地址空间,可以去看看底层自动拆箱装箱是如何完成的,研究一下常量池也会明白这样设计的原因,如果对这方面感兴趣,可以去研究一下《深入jvm虚拟机》,我也准备去看看,可以一起研究
作者: 18366882177    时间: 2016-9-2 08:52
Integer a=new Integer(3);会创建个值为3的对象地址放在堆内存中
而int a=3,在栈内存中有个变量a只为3.
==号   基本类型比较值,引用类型比较地址
equals  字符串比较内容  引用型默认比较内容
作者: a953558401    时间: 2016-9-2 22:12
简单点说就是equals比较的是值是否相同,而==号呢,比较的是地址值. Integer i=new Integer(3);                 Integer j=new Integer(3);他们分别都new了一次,那就是他们的地址是不同的,所以(i==j) 是false.而.equals比较的是值,那不用看就知道是true.
作者: WHH123    时间: 2016-9-2 22:59
一楼说的很简洁
作者: Esen    时间: 2016-9-2 23:02
Integer类是int行数据的包装类, Integer i=new Integer(3);  和 Integer j=new Integer(3);是创建了两个Integer对象,当用"=="符比较两个对象时,比较的是地址,地址相同返回true;而Integer继承Object类并重写了equals方法,只要两个对象的int值相等就返回true.另外,Java中存在字节常量池,   Integer i1=3;   Integer j1=3;这两个地址相同,因为3在-128到127之间,当在这个范围给Integer对象赋值时,不会重新创建对象,例如Integer  a = 188;  Integer  b = 188;这两个就是两个不同的对象,如果用"=="比较,则返回false,而equals方法只要值相等就返回true.
作者: Esen    时间: 2016-9-2 23:04
Integer类是int行数据的包装类, Integer i=new Integer(3);  和 Integer j=new Integer(3);是创建了两个Integer对象,当用"=="符比较两个对象时,比较的是地址,地址相同返回true;而Integer继承Object类并重写了equals方法,只要两个对象的int值相等就返回true.另外,Java中存在字节常量池,   Integer i1=3;   Integer j1=3;这两个地址相同,因为3在-128到127之间,当在这个范围给Integer对象赋值时,不会重新创建对象,例如Integer  a = 188;  Integer  b = 188;这两个就是两个不同的对象,如果用"=="比较,则返回false,而equals方法只要值相等就返回true.
作者: Esen    时间: 2016-9-2 23:05
Integer类是int行数据的包装类, Integer i=new Integer(3);  和 Integer j=new Integer(3);是创建了两个Integer对象,当用"=="符比较两个对象时,比较的是地址,地址相同返回true;而Integer继承Object类并重写了equals方法,只要两个对象的int值相等就返回true.另外,Java中存在字节常量池,   Integer i1=3;   Integer j1=3;这两个地址相同,因为3在-128到127之间,当在这个范围给Integer对象赋值时,不会重新创建对象,例如Integer  a = 188;  Integer  b = 188;这两个就是两个不同的对象,如果用"=="比较,则返回false,而equals方法只要值相等就返回true.
作者: 足球骑士szw    时间: 2016-9-23 23:25
没看懂..........看来还要慢慢学习
作者: stonelove    时间: 2016-10-26 09:27
大爱黑马 希望每个人都有自己的成功
作者: 1134323536    时间: 2016-12-7 10:40
一个引用和另外一个常量

作者: 叶宇光    时间: 2016-12-8 23:05
一个在堆内存一个在常量池





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2