java对象相等问题

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

                       
public class TestA {    private Integer a;    public Integer getA() {        return a;    }    public void setA(Integer a) {        this.a = a;    }}public class Test {    public static void main(String[] args) {        TestA a = new TestA();        a.setA(1);        TestA aa = a;        a.setA(3);        System.out.println(aa==a);        System.out.println(aa.getA());    }}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

输出结果是true和3,这理解起来很简单,java中对象直接”=”赋值其实就是将引用传给对方,让他也指向同一个内存地址。
所以如果a改变了里面属性的值,那这个地址存储的内容就变了,当aa去拿的时候就是变了之后的,因为两个指向依然同一个地址,
所以aa==a是true的。
但如果这么来:

  TestA a = new TestA();        a.setA(1);        TestA aa = a;  a = new TestA();        a.setA(3);        System.out.println(aa==a);        System.out.println(aa.getA());
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

那输出就是false和1了,因为a又重新new了一个对象,他引用的地址已经变了,就和aa一点关系都没有了!

以上我们都知道,但对于包装类却看似不一样:

public class Test {    public static void main(String[] args) {        Integer b = new Integer(5);        Integer c = b;        System.out.println(b==c);        b = b+1;        System.out.println(b);        System.out.println(c);        System.out.println(b==c);    }}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

以上的运行结果是:
true
6
5
false
这似乎和我们之前的例子不一样了。c和b都指向同一个地址,所以第一次b==c是true的,但当b加1之后,c并没有跟着b加1,
b==c变成了false,说明两个指向的地址已经不是同一个了。
一开始对这个可能无法理解,我们先看看下面的例子:

public class Test {    public static void main(String[] args) {        int x = 1;        int y = x;        x = x+1;        System.out.println(y==x);    }}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

输出是false,这个我们很容易知道,一开始x和y都是1,当x加1之后,x是2,y还是1,所以y==x是false的,数值型的变量在判断==时是直接比较他们的值的。

再回忆一下java的装箱和拆箱:
所谓装箱,就是把基本类型用它们相对应的引用类型包起来,使它们可以具有对象的特质,如我们可以把int型包装成Integer类的对象,或者把double包装成Double,等等。
 所谓拆箱,就是跟装箱的方向相反,将Integer及Double这样的引用类型的对象重新简化为值类型的数据。
JDK1.5之后可自动进行装箱和拆箱的操作,例子如下:

int i=10;Integer j=Integer.valueOf(i); //手动装箱操作int k=j.intValue();//手动拆箱操作int i1=10Integer j1=i1;//自动装箱操作int k1=j1;//自动拆箱操作
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

通过上面的讲解应该就知道原因了:

    Integer b = new Integer(5);    Integer c = b;    System.out.println(b==c);//现在两个指向同一个地址,是true的    b = b+1;//b是包装类,得拆箱成数值型,然后加1,变成数值6,然后把数值6再装箱变成包装类赋给b,等同于b=Integer.valueOf(b.intValue()+1);    //Integer.valueOf()会生成一个新的包装类对象(因为valueOf()方法的源码里写着,return的是new Integer(),源码见下)    System.out.println(b==c);//现在两个指向不同的地址,是false的
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

终于真相大白了,上面的问题告一段落,我自以为对包装类很懂了,但再看看下面的题目:

    Integer b = 128;    Integer c = 128;    System.out.println(b==c);
   
   
  • 1
  • 2
  • 3

输出是false,这很好理解,128是数值型的,再赋值给包装类变量时先要装箱,上面的等同于:

        Integer b = Integer.valueOf(128);        Integer c = Integer.valueOf(128);        System.out.println(b==c);
   
   
  • 1
  • 2
  • 3

这样很明显可以看成是false的,是两个不同的对象。
再看看这个:

        Integer b = 100;        Integer c = 100;        System.out.println(b==c);
   
   
  • 1
  • 2
  • 3

输出居然是true。小学生表示已经崩溃,是不是对java已经无爱了。但是我可不会就这样放弃,到底是什么原因呢?
查看Integer的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);}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

于是明白了,在【-128,127】之间的数字,valueOf()返回的是缓存中的对象,所以两次调用返回的是同一个对象。
也就是说Integer(100)这样的对象已经有了一个了,自动装箱之前就不去new了,直接使用缓存里的,所以是同一个对象,指向的是同一个引用地址。
以上代码等同于:

        Integer b = Integer.valueOf(100);        Integer c = Integer.valueOf(100);        System.out.println(b==c);
   
   
  • 1
  • 2
  • 3

所以输出是true。
接下来下面这个也很明白了吧:

    Integer a = new Integer(100);      Integer b = 100;      System.out.println(a == b);
   
   
  • 1
  • 2
  • 3

输出的是false,因为a是自己new的对象,不是通过valueOf获取的,没有放进缓存里,所以b在valueOf时还是会new一个
以上代码等同于:

    Integer a = new Integer(100);      Integer b = Integer.valueOf(100);      System.out.println(a == b);
   
   
  • 1
  • 2
  • 3

这样就看的出来是false了。
总之以上的现象只会在拆装箱,或者你自己手动调用valueOf方法时才会出现!

           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow

这里写图片描述

猜你喜欢

转载自blog.csdn.net/aabbyyz/article/details/83509972