前言
笔者最近面试时碰到了一道面试题,个人觉得出得挺好的,特此记录以供大家一起学习。
public class Demo {
public static void main(String args[]) {
System.out.println(new Simpson("Bart").equals(new Simpson("Bart")));
Simpson overriddenHomer = new Simpson("Homer") {
public int hashCode() {
return (43 + 777) + 1;
}
};
System.out.println(new Simpson("Homer").equals(overriddenHomer));
Set set = new HashSet(Set.of(new Simpson("Homer"), new Simpson("Marge")));
set.add(new Simpson("Homer"));
set.add(overriddenHomer);
System.out.println(set.size());
}
static class Simpson {
String name;
Simpson(String name) {
this.name = name;
}
@Override
public boolean equals(Object object) {
Simpson otherSimpson = (Simpson) object;
return this.name.equals(otherSimpson.name) && this.hashCode() == otherSimpson.hashCode();
}
@Override
public int hashCode() {
return (43 + 777);
}
}
}
问题:上述代码运行结果是()
A)true true 4
B)true false 3
C)true false 2
D)false true 3
我的解题过程:
-
第一个输出结果
System.out.println(new Simpson("Bart").equals(new Simpson("Bart")));
内部类 Simpson 定义了新的构造函数,重写了 equals 和 hashCode 方法。在这两个对象 equals 时要根据重写后的方法来判断返回值。重写后的 equals 方法的判断条件有两个:1. 内部 String 变量 name 的字符串比较。2. 重写后的 hashCode 方法返回值比较。
这里两个 Simpson 对象的内部变量 name 都是在创建对象时通过构造函数赋的值,且构造函数传参都是 “Bart”,所以两个对象的 name 值都是 “Bart” ,String 类型的原生 equals 方法实现原理是将 String 转成 char 数组并按下标逐一对比是否相等,由此可知条件一是满足的。
又因为重写后的 hashCode 方法返回值是固定的 (43 + 777),遂两个对象的 hashCode 方法返回值肯定也是相同的,至此第二个条件也满足。可以得出第一项输出值为 true。
public boolean equals(Object object) { Simpson otherSimpson = (Simpson) object; return this.name.equals(otherSimpson.name) && this.hashCode() == otherSimpson.hashCode(); } public int hashCode() { return (43 + 777); }
-
第二个输出
System.out.println(new Simpson("Homer").equals(overriddenHomer));
题中在创建 overriddenHomer 对象时很调皮的再次重写了 hashCode 方法,所以该对象 hashCode 方法的返回值是重写后的值,也就是 (43 + 777) + 1,与对象原方法返回值不同。“&&” 是逻辑与,"&&" 两边条件同时满足时才会返回 true, 由此可知第二项输出值为 false。
-
第三个输出
System.out.println(set.size());
Set.of() 函数是 jdk1.9 才开始有的新特性,该方法主要是为了像题中一样快速往 HashSet 中添加元素。
题中在创建 set 对象时就添加了 “Homer”、“Marge” 两个元素。由于 HashSet 自带去重机制,去重原理就是在 add 函数被调用时会调用对象的 HashCode 函数,并比对返回结果,如果结果不相同则直接添加,但如果结果相同的话则会调用元素对象的 equals 方法再次比对,如果equals 方法返回 false 则添加,否则不允许添加。会覆盖已有的元素。总结,HashSet 添加元素时如果元素的 hashCode 值相同并且 equals 返回 true 时,元素不会被正常添加。(重点)
由此可知,第一个 “Homer” 与 “Marge” 虽然 hashCode 返回值相同,但重写的 equals 方法因为两者 name 值不同返回为 false,所以两者都正常添加。第二个出现的 “Homer” hashCode 与 name 值都相同,在添加时由于 hashCode 返回值相同且equals 方法返回 true 没有被正常添加。最后 overriddenHomer 对象虽然 name 值与 “Homer” 相同,但由于该对象再次重写了 HashCode 方法,HashCode 返回值与 name 为 “Homer” 的对象 HashCode 返回值不同,可以正常添加。至此可知 set 对象中只有三个元素被成功添加,第三项输出值应该是 3。