==
(或者!=
) : 关系运算符,既可以用于基本类型的数值相等性比较,也可以用于对象引用之间的关系判断,此时是对象引用等价性比较,即是否都是同一个对象的引用(引用地址是否相同)[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
),也可能不是别人认识的张三(==
返回false
而equals
返回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源码。
参考:
- [1]15.21.3. Reference Equality Operators == and != https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.21.3
- [2]《On Java8》(即 Java编程思想 第5版) 第四章运算符:关系运算符,中文开源版请参考 https://github.com/lingcoder/onJava8/