一、String类equals()方法
Object类,equals()方法,默认两个对象==,即内存地址相同,即对象相等。
public boolean equals(Object o) {
return this == o;
}
两个内存地址不同的对象比较时,肯定结果不同,为实现对象在某些情况下比较时相等,子类重写equals()方法,如String类,两个String对象每个字符相同时,自定义equal()相等。
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = length();
if (n == anotherString.length()) {
int i = 0;
while (n-- != 0) {
if (charAt(i) != anotherString.charAt(i))
return false;
i++;
}
return true;
}
}
return false;
}
String类equals()方法,如果==相等,指向同一内存,一定相等。类型不同时,一定不相等,比较每一个字符相同,认为两个字符串String对象相等。
二、自定义
自定义一个User类。
private String id;
private String name;
private String city;
public User(String id, String name, String city) {
super();
this.id = id;
this.name = name;
this.city = city;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
三个参数,id,name和city,重写equals()方法,定义id相等时,两个User对象相等,比较id的equals()方法。
针对自定义设计实体类重写,比较类中特定元素定义对象相等。
重写String类equal()方法,两个String对象,字符串相同,认为它们相等,但是,在HashSet集合类判断对象相等时,依然会保存两个相同字符的String对象,说明HaseSet认为两个相同字符的String对象不是相等对象。
HashSet集合类相等对象仅存储一份。
用User类的例子说明,仅重写equals()方法。
User user1=new User("1","ch","shanghai");
User user2=new User("1","ch2","beijing");
System.out.println(user2==user1);//false,内存不同
System.out.println(user2.equals(user1));//true,定义id相同的User对象相等
HashSet<User> hashSet=new HashSet();
hashSet.add(user1);
hashSet.add(user2);
System.out.println(hashSet.size());
HashSet集合类认为两个User是不同对象。
HashSet类,hashCode值相同且equals()相等,才是相等对象。在User类,仅重写equal()方法,未重写hashCode()方法,两个对象hash值按基类Object方法计算。
Object基类hashCode()方法,根据内存地址的hash算法计算,两个地址不同的对象hashCode值不同,因此,若HashSet类认定是相同对象,需重写hashCode方法。
三、String类hashCode()方法
public int hashCode() {
int h = hash;
final int len = length();
if (h == 0 && len > 0) {
for (int i = 0; i < len; i++) {
h = 31 * h + charAt(i);
}
hash = h;
}
return h;
}
按照每个字符计算hash值,如果两个字符串相同时,hashCode值相等,重写User类的hashCode()方法。
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
比较id的hashCode(),如果字符串id是字符相同,那么hashCode()相等,这样,两个User对象的hashCode()相等,equals()相等,HashSet集合类只存储一份。
User user1=new User("1","ch","shanghai");
User user2=new User("1","ch2","beijing");
HashSet<User> hashSet=new HashSet();
hashSet.add(user1);
hashSet.add(user2);
HashMap<User,String>hashMap=new HashMap();
hashMap.put(user1, "str1");
hashMap.put(user2,"str2");
System.out.println(user1);
System.out.println(user2);
System.out.println(user2==user1);
System.out.println(user1.hashCode());
System.out.println(user2.hashCode());
System.out.println(user2.equals(user1));
System.out.println(hashSet.size());
System.out.println(hashMap.size());
打印值
User [id=1, name=ch, city=shanghai]
User [id=1, name=ch2, city=beijing]
false
80
80
true
1
1
HashMap类,先hashCode()方法,遍历key的hashCode是否相同,hashCode()相等时,落到同一个bucket中。
再比较equals()方法,相等,说明key已存,直接更新。如果不重写hashCode()方法,永远不会保存到数组的同一个bucket中。
四、总结
两个对象==相等,同一个内存地址,hashCode()方法相等,equals()方法相等。
两个对象hashCode()方法相等,equals()方法不一定相同,参考HashMap类hashcode冲突处理。
两个对象equals()方法相等,如果未重写hashCode()方法,hashCode()不会相等,根据基类Object按照内存地址hash,HashSet类集合类会出现问题。
任重而道远
网友评论