Java基础(007):关系运算符==和equals的区别

  • ==(或者 != ) : 关系运算符,既可以用于基本类型的数值相等性比较,也可以用于对象引用之间的关系判断,此时是对象引用等价性比较,即是否都是同一个对象的引用(引用地址是否相同)[1]。从另一个角度看,本质上也是数值比较,只是这里的数值是引用地址/内存地址而已。
  • equals : 是一个实例方法,存在于Java的顶层父类Object中,因此所有类都会继承,而且只能作用于对象间的比较,而基本类型不属于引用类型,所以equals并不适用于基本类型间的判断(可以是 包装器类型.equals(原始数据类型),原始数据类型会自动装箱)。equals方法也是用于两个对象的相等性判断,不过这种等价性判断需要根据是否重写equals方法来具体区分。

  Object.equals(Object obj)方法具体如下:

public boolean equals(Object obj) {
    return (this == obj);
}

  可以看到,原始的equals方法实质上就是用==做判断,也即是引用地址的等价性判断。实际上很多时候会在子类中重写equals方法,按需实现等价性判断。因此equals方法的等价性判断主要有以下2种场景:

  • 场景1:子类使用默认的 Object.equals(Object obj) 而不重写,此时可以看作等价于==,即对象引用地址的等价性判断。
  • 场景2:按需重写equals方法,此时一般用于对象内容等价性的判断,这种场景下,在指定的内容一致时我们可以认为对象是相等/等价的,Java API 中比较典型的应用有以下几种:
    • 集合框架实现类中的元素等价性判断
    • String 类
    • 基本类型的包装类

  另外需要注意的是:对于==返回true的对象判断,equals肯定也是返回true,因为引用地址一样,都是指向同一个对象;反过来equals返回true不一定意味着是指向同一个对象,还很可能只是对象的内容一样而已。例如名字为 “张三”的可能会有很多个人,你认识的张三可能也是别人认识的张三(==equals都返回true),也可能不是别人认识的张三(==返回falseequals返回true),但名字确实都是张三。

  综合案例(github传送门)如下:

public class RelationalOperatorsVsEquals {
    public static void main(String[] args) {
        Integer int1 = -128;
        Integer int2 = -128;
        // 实际上 int1 和 int2 都是 Integer 缓冲池[-128,127] 中的同一个缓存对象
        System.out.println("int1 == int2 : " + (int1 == int2));
        System.out.println("int1.equals(int2) : " + (int1.equals(int2)));
        
        Integer int3 = 128;
        Integer int4 = 128;
        // 此时的 int3 和 int4 指向的2个完全不同的对象,但是内部数值其实是等价的
        System.out.println("int3 == int4 : " + (int3 == int4));
        System.out.println("int3.equals(int4) : " + (int3.equals(int4)));
        
        String str1 = "ZhangSan";
        String str2 = "ZhangSan";
        // 实际上 str1 和 str2 都是指向常量池上的 "ZhangSan"
        System.out.println("str1 == str2 : " + (str1 == str2));
        System.out.println("str1.equals(str2) : " + (str1.equals(str2)));
        
        String str3 = new String("ZhangSan");
        String str4 = new String("ZhangSan");
        // 此时的 str3 和 str4 指向的不同的堆对象 "ZhangSan"
        System.out.println("str3 == str4 : " + (str3 == str4));
        System.out.println("str3.equals(str4) : " + (str3.equals(str4)));
        System.out.println("str1 == str3 : " + (str1 == str3));
        System.out.println("str1.equals(str3) : " + (str1.equals(str3)));
    }
}

// ......
// result
int1 == int2 : true
int1.equals(int2) : true
int3 == int4 : false
int3.equals(int4) : true
str1 == str2 : true
str1.equals(str2) : true
str3 == str4 : false
str3.equals(str4) : true
str1 == str3 : false
str1.equals(str3) : true

注:更多关于equals的说明,建议先参考Object.equals(Object obj)详细的API文档说明(源码javadoc注释)。后续笔者将在集合框架的相关说明中进一步讲解(和 hashCode 方法等)。

注:关于String、包装类对equals方法重写的具体实现,同样还是建议直接参考相关的JDK API源码。

参考:

 

posted @ 2021-02-06 22:20  心明谭  阅读(163)  评论(0编辑  收藏  举报