JAVA中 ==和Equals的区别

130 阅读3分钟

先初步了解JAVA中的内存模型

JVM中,内存分为堆内存跟栈内存。他们二者的区别是: 当我们创建一个对象(new Object)时,就会调用对象的构造函数来开辟空间,将对象数据存储到堆内存中,与此同时在栈内存中生成对应的引用,当我们在后续代码中调用的时候用的都是栈内存中的引用。还需注意的一点,基本数据类型是存储在栈内存中。

== 比较的是变量(栈)内存中存放的对象的(堆)内存地址,用来判断两个对象的地址是否相同,即是否是指相同一个对象。比较的是真正意义上的指针操作,两边的操作数必须是同一类型才能编译通过。

对于基本数据类型的变量,如:byte,short,char,int,long,float,double,boolean **==**是直接对其值进行比较。如:

int a = 10;
double b = 10.0;
System.out.println(a==b); //true

是因为这里a和b都指向地址为10的堆。

对于字符串类型的比较,如:

String a = new String("abc");
String b = new String("abc");
String c = "abc";
String d = "abc";
System.out.println(a==b); //false
System.out.println(a==c); //false
System.out.println(c==d); //true

a==b 为false是因为每new一次对象就会在堆内存上生成一个新的地址,同理 a==c也为false

c==d 为true是因为 String c ="abc" 先在栈中创建对象的引用c,然后查找栈中有没有存放“abc”,如果没有,则将“abc”存放进栈,并将c指向“abc”,如果已经有“abc”,则直接将c指向“abc”。

对于包装类型的比较,如:

Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
Double d1 = 10.0;
Double d2 = 10.0;
System.out.println(i1==i2); //true
System.out.println(i3==i4); //false
System.out.println(d1==d2); //false

因为如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。d1 ==d2 为false 是因为double是有精度的

equals是用来比较两个对象的内容是否一样,由于所有的类都是继承自java.lang.Object类的,所以适用于所有对象,如果没有对该方法进行重写的话,调用的仍然是Object类中的方法,而Object中的equals方法返回的却是==的判断。

如String 和封装类型都是因为重写了equals方法,方法中对值得比较做了处理

如Double中的equals:

    public boolean equals(Object obj) {
        return (obj instanceof Double)
               && (doubleToLongBits(((Double)obj).value) ==
                      doubleToLongBits(value));
    }

例如重写User中的equals方法

@Override
public boolean equals(Object obj) {
    if(this == obj){
        return true;//地址相等
    }
    if(obj == null){
        return false;//非空性:对于任意非空引用x,x.equals(null)应该返回false。
    }
    if(obj instanceof User){
        User other = (User) obj;
        //需要比较的字段相等,则这两个对象相等
        if(equalsStr(this.name, other.name)
           && equalsStr(this.age, other.age)){
            return true;
        }
    }
​
    return false;
}
​
private boolean equalsStr(String str1, String str2){
    if(StringUtils.isEmpty(str1) && StringUtils.isEmpty(str2)){
        return true;
    }
    if(!StringUtils.isEmpty(str1) && str1.equals(str2)){
        return true;
    }
    return false;
}
User user1 = new User("hjw", "18");
User user2 = new User("hjw", "18");
System.out.println((user1.equals(user2))); //true

这样就是用来比较两个对象的内容是否一样,否则调用的仍然是Object类中的方法,判断的仍然是两个对象的地址相等,如Object中的源码:

public boolean equals(Object obj) {
        return (this == obj);//地址相等
}

总结:

==用来判断两个对象的地址是否相同,equals用来比较两个对象的内容是否一样,但是需要在对象中重写equals方法,否则还是会调用Object中的方法,依然是判断两个对象的地址