对于Object来说
- 对于 Object 对象来说,equals 和 == 都是一样的,都是比较对象的引用是否相同。
对于JDK中其他类来说
JDK中的其他类中通常会重写equals以实现具体的值比较,例如Integer中的equals和String中的equals等。
Integer中equals源码实现
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
Integer 中会先将 Integer 对象转换成基础类型 int 值来进行比较,此时就不是比较对象的引用了。
String中equals源码实现
1. equals 方法(实例方法)
public boolean equals(Object anObject) {
if (this == anObject) { // 引用相同,值也相同,返回true
return true;
}
return (anObject instanceof String aString)
&& (!COMPACT_STRINGS || this.coder == aString.coder)
&& StringLatin1.equals(value, aString.value);
}
代码逐步解析:
-
this == anObject:- 首先检查当前对象
this是否与传入的对象anObject是同一个引用。 - 如果引用相同,则直接返回
true,因为同一个引用意味着两者的内容必然相同。
- 首先检查当前对象
-
anObject instanceof String aString:- 检查传入的对象
anObject是否是一个String类型。 - 如果是,则使用 Java 14 引入的 模式匹配(Pattern Matching) 语法,将其转化为变量
aString,以便后续操作。 - 如果
anObject不是String类型,则直接返回false(完全不可能相等)。
- 检查传入的对象
-
!COMPACT_STRINGS || this.coder == aString.coder:COMPACT_STRINGS是一个内部标志,指示是否启用了紧凑字符串优化(Compact Strings,Java 9 引入)。- Compact Strings:如果字符串只包含 Latin-1 字符,那么它会使用更节省空间的 Latin-1 编码(1 字节表示一个字符)。否则,使用 UTF-16 编码(2 字节表示一个字符)。
- 如果紧凑字符串优化未启用,直接跳过该检查。
- 如果启用了紧凑字符串优化,则需要检查两者的
coder值是否一致:coder是一个内部字段,表示字符串的编码(Latin-1 或 UTF-16)。- 如果两者的编码不同,则返回
false。
-
StringLatin1.equals(value, aString.value):- 如果编码一致,调用内部方法
StringLatin1.equals对比两个字符串的实际字节数组value。 value是字符串对象内部存储的字节数组。- 如果字节数组完全相等,则返回
true,否则返回false。
- 如果编码一致,调用内部方法
2. equals 方法(静态方法)
@IntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
if (value.length == other.length) {
for (int i = 0; i < value.length; i++) {
if (value[i] != other[i]) {
return false;
}
}
return true;
}
return false;
}
代码逐步解析:
-
@IntrinsicCandidate注解:- 这是一个 JVM 内部优化提示,表示这个方法可能被 JVM 内联优化为高效的机器指令。
- 它通常不影响代码行为,但可以提升性能。
-
value.length == other.length:- 首先检查两个字节数组的长度是否相等。
- 如果长度不同,则两个字符串显然不可能相等,直接返回
false。
-
字符逐个比较:
- 如果长度相等,则逐个比较两个字节数组中的每个字节。
- 如果发现有任意一个字节不相等,立即返回
false。
-
全部相等的情况:
- 如果整个循环执行完毕,没有发现不匹配的字节,则说明两个数组完全相等,返回
true。
- 如果整个循环执行完毕,没有发现不匹配的字节,则说明两个数组完全相等,返回
从 String 中的 equals 中可以看出,它也是将 Object 中的引用比较重写成了值比较了
总结
对于 Object 来说,== 和 equals 都是一样的,都是用来对比两个对象的引用是否相同的,而其他 JDK 中的类,如 String 或 Integer 等,通常都会重写 equals 让其变为比较具体的值是否相同,而非引用是否相同。我们通常会使用 == 来对比两个对象的引用是否相同,使用 equals 对比两个值是否相同(前提是重写了 equals 方法)。