面试官的考察点
这道题仍然是考察JVM层面的基本知识,面试官认为,基本功扎实,才能写出健壮性和稳定性很高的代码。
涉及到的技术知识
(x.equals(y)==true)
,这段代码,看起来非常简单,但其实里面还是涉及了一些底层知识点的,首先我们基于equals
这个方法进行探索。
equals
这个方法,在每个对象中都存在,以String类型为例,其方法定义如下
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) { //判断对象实例是否是String
String anotherString = (String)anObject; //强转成string类型
int n = value.length;
if (n == anotherString.value.length) { //如果两个字符串相等,那么它们的长度自然相等。
//遍历两个比较的字符串,转换为char类型逐个进行比较。
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i]) //采用`==`进行判断,如果不相同,则返回false
return false;
i++;
}
return true; //否则返回true。
}
}
return false;
}
首先来分析第一段代码,判断传递进来的这个对象和当前对象实例this
是否相等,如果相等则返回true
。
if (this == anObject) {
return true;
}
那==
号的处理逻辑是怎么实现的呢?
了解==
判断
在java语言中==
操作符号,这个比较大家都知道,是基于引用对象的比较,具体其实还有一些其他的区别。
JVM会根据==
两边相互比较的操作类型不同,在编译时生成不同的指令。
-
对于boolean,byte、short、int、long这种整形操作数,会生成
if_icmpne
指令,该指令用于比较整形数值是否相等。关于if_icmpne指令可以参见:Chapter 4. The class File Format,它在Hotspot VM中的bytecodeInterpreter源码中的具体实现如下#define COMPARISON_OP(name, comparison) CASE(_if_icmp##name): { int skip = (STACK_INT(-2) comparison STACK_INT(-1)) ? (int16_t)Bytes::get_Java_u2(pc + 1) : 3; address branch_pc = pc; UPDATE_PC_AND_TOS(skip, -2); DO_BACKEDGE_CHECKS(skip, branch_pc); CONTINUE; }
可以看到实质是按照comparison表达式比较操作数栈中偏移量为-1和-2的两个INT值。
-
如果操作数是对象的话,编译器则会生成if_acmpne指令,与if_icmpne相比将i(int)改成了a(object reference)。这个指令在JVM规范中的表述:Chapter 4. The class File Format,它在Hotspot VM中相应的实现可参考:
COMPARISON_OP(name, comparison) CASE(_if_acmp##name): { int skip = (STACK_OBJECT(-2) comparison STACK_OBJECT(-1)) ? (int16_t)Bytes::get_Java_u2(pc + 1) : 3; address branch_pc = pc; UPDATE_PC_AND_TOS(skip, -2); DO_BACKEDGE_CHECKS(skip, branch_pc); CONTINUE; }
从
STACK_OBJECT(-2) comparison STACK_OBJECT(-1)
这一句即可看出比较的其实是操作数栈上两个对象在堆中的指针。
对于JVM有一定了解的同学,必然知道((x==y)=true)
这个判断,如果x
和y
的内存地址相同,那么意味着就是同一个对象,因此直接返回true
。
因此从上面的分析中,得到的结论是,
==
判断,比较的是两个对象的内存地址,如果==
返回true,说明内存地址相同。
String.equals源码
继续分析equals
中的源码,剩余部分源码的实现逻辑是
-
比较两个字符串的长度是否相等,如果不相等,直接返回
false
-
把两个String类型转换为char[]数组,并且按照数组顺序逐步比较每一个char字符,如果不相等,同样返回
false
public boolean equals(Object anObject) {
//省略
if (anObject instanceof String) { //判断对象实例是否是String
String anotherString = (String)anObject; //强转成string类型
int n = value.length;
if (n == anotherString.value.length) { //如果两个字符串相等,那么它们的长度自然相等。
//遍历两个比较的字符串,转换为char类型逐个进行比较。
char v1[] = value;
c