面試官:重寫 equals 時(shí)為什么一定要重寫 hashCode?


當(dāng)我們對比兩個(gè)對象是否相等時(shí),我們就可以先使用 hashCode 進(jìn)行比較,如果比較的結(jié)果是 true,那么就可以使用 equals 再次確認(rèn)兩個(gè)對象是否相等,如果比較的結(jié)果是 true,那么這兩個(gè)對象就是相等的,否則其他情況就認(rèn)為兩個(gè)對象不相等。這樣就大大的提升了對象比較的效率,這也是為什么 Java 設(shè)計(jì)使用 hashCode 和 equals 協(xié)同的方式,來確認(rèn)兩個(gè)對象是否相等的原因。
?
1.equals 方法
public?boolean?equals(Object?obj)?{
????return?(this?==?obj);
}
public?class?EqualsMyClassExample?{
????public?static?void?main(String[]?args)?{
????????Person?u1?=?new?Person();
????????u1.setName("Java");
????????u1.setAge(18);
??
????????Person?u2?=?new?Person();
????????u1.setName("Java");
????????u1.setAge(18);
????????
????????//?打印?equals?結(jié)果
????????System.out.println("equals 結(jié)果:"?+?u1.equals(u2));
????}
}
class?Person?{
????private?String?name;
????private?int?age;
????public?String?getName()?{
????????return?name;
????}
????public?void?setName(String?name)?{
????????this.name?=?name;
????}
????public?int?getAge()?{
????????return?age;
????}
????public?void?setAge(int?age)?{
????????this.age?=?age;
????}
}

2.hashCode 方法
public?native?int?hashCode();
hashCode 使用
public?class?HashCodeExample?{
????public?static?void?main(String[]?args)?{
????????String?s1?=?"Hello";
????????String?s2?=?"Hello";
????????String?s3?=?"Java";
????????System.out.println("s1?hashCode:"?+?s1.hashCode());
????????System.out.println("s2?hashCode:"?+?s2.hashCode());
????????System.out.println("s3?hashCode:"?+?s3.hashCode());
????}
}

public?class?HashCodeExample?{
????public?static?void?main(String[]?args)?{
????????String?s1?=?"Aa";
????????String?s2?=?"BB";
????????System.out.println("s1?hashCode:"?+?s1.hashCode());
????????System.out.println("s2?hashCode:"?+?s2.hashCode());
????}
}

?
3.為什么要一起重寫?
3.1 Set 正常使用
import?java.util.HashSet;
import?java.util.Set;
public?class?HashCodeExample?{
????public?static?void?main(String[]?args)?{
????????Set?set?=?new?HashSet();
????????set.add("Java");
????????set.add("Java");
????????set.add("MySQL");
????????set.add("MySQL");
????????set.add("Redis");
????????System.out.println("Set?集合長度:"?+?set.size());
????????System.out.println();
????????//?打印?Set?中的所有元素
????????set.forEach(d?->?System.out.println(d));
????}
}

3.2 Set 集合的“異?!?/span>
import?java.util.HashSet;
import?java.util.Objects;
import?java.util.Set;
public?class?EqualsExample?{
????public?static?void?main(String[]?args)?{
????????//?對象?1
????????Persion?p1?=?new?Persion();
????????p1.setName("Java");
????????p1.setAge(18);
??????? //?對象?2
????????Persion?p2?=?new?Persion();
????????p2.setName("Java");
????????p2.setAge(18);
??????? //?創(chuàng)建?Set?集合
????????Set?set?=?new?HashSet ();
????????set.add(p1);
????????set.add(p2);
?????? //?打印?Set?中的所有數(shù)據(jù)
????????set.forEach(p?->?{
????????????System.out.println(p);
????????});
????}
}
class?Persion?{
????private?String?name;
????private?int?age;
????//?只重寫了?equals?方法
????@Override
????public?boolean?equals(Object?o)?{
????????if?(this?==?o)?return?true;?//?引用相等返回?true
????????//?如果等于?null,或者對象類型不同返回?false
????????if?(o?==?null?||?getClass()?!=?o.getClass())?return?false;
????????//?強(qiáng)轉(zhuǎn)為自定義?Persion?類型
????????Persion?persion?=?(Persion)?o;
????????//?如果?age?和?name?都相等,就返回?true
????????return?age?==?persion.age?&&
????????????????Objects.equals(name,?persion.name);
????}
?
????public?String?getName()?{
????????return?name;
????}
????public?void?setName(String?name)?{
????????this.name?=?name;
????}
????public?int?getAge()?{
????????return?age;
????}
????public?void?setAge(int?age)?{
????????this.age?=?age;
????}
????
?????@Override
????public?String?toString()?{
????????return?"Persion{"?+
????????????????"name='"?+?name?+?'\''?+
????????????????",?age="?+?age?+
????????????????'}';
????}
}

3.3 解決“異?!?/span>
import?java.util.HashSet;
import?java.util.Objects;
import?java.util.Set;
public?class?EqualsToListExample?{
????public?static?void?main(String[]?args)?{
????????//?對象?1
????????Persion?p1?=?new?Persion();
????????p1.setName("Java");
????????p1.setAge(18);
?????? //?對象?2
????????Persion?p2?=?new?Persion();
????????p2.setName("Java");
????????p2.setAge(18);
?????? //?創(chuàng)建?Set?對象
????????Set?set?=?new?HashSet ();
????????set.add(p1);
????????set.add(p2);
?????? //?打印?Set?中的所有數(shù)據(jù)
????????set.forEach(p?->?{
????????????System.out.println(p);
????????});
????}
}
class?Persion?{
????private?String?name;
????private?int?age;
????@Override
????public?boolean?equals(Object?o)?{
????????if?(this?==?o)?return?true;?//?引用相等返回?true
????????//?如果等于?null,或者對象類型不同返回?false
????????if?(o?==?null?||?getClass()?!=?o.getClass())?return?false;
????????//?強(qiáng)轉(zhuǎn)為自定義?Persion?類型
????????Persion?persion?=?(Persion)?o;
????????//?如果?age?和?name?都相等,就返回?true
????????return?age?==?persion.age?&&
????????????????Objects.equals(name,?persion.name);
????}
????@Override
????public?int?hashCode()?{
????????//?對比?name?和?age?是否相等
????????return?Objects.hash(name,?age);
????}
????
????public?String?getName()?{
????????return?name;
????}
????public?void?setName(String?name)?{
????????this.name?=?name;
????}
????public?int?getAge()?{
????????return?age;
????}
????public?void?setAge(int?age)?{
????????this.age?=?age;
????}
????
????@Override
????public?String?toString()?{
????????return?"Persion{"?+
????????????????"name='"?+?name?+?'\''?+
????????????????",?age="?+?age?+
????????????????'}';
????}
}

3.4 原因分析
?
總結(jié)
有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)
歡迎大家關(guān)注Java之道公眾號
好文章,我在看??
