可變對象:指創建後自身的哈希值可能被改變的對象。
hashMap儲存鍵值對方式
插入
HashMap用Key的哈希值來存儲和查找鍵值對。當插入一個value時,HashMap會計算Key的哈希值然後把value和這個哈希值相關聯。
查找
HashMap通過計算Key的哈希值查找相關聯的value。
問題
如果key的類型是一個可變對象那就會出現問題,比如以下代碼
public static void main(String[] args) {
Map<User,Integer>map=new HashMap<>();
User user=new User(1);
System.out.println("初始hash:"+user.hashCode());
map.put(user,11);
user.setName("11");
System.out.println("賦值後的hash:"+user.hashCode());
System.out.println(map.get(user));
}
class User {
private int id;
private String name;
public User(final int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
運行結果:
初始hash:3524
賦值後的hash:5049
null
這裏的user是可變對象。當改變user的屬性時其hash值發生了變化,map中是查找不到對應的值的
解決方法
改變可變對象的hash方法,通過改變user的hash方法使其name不參與hash計算,並使其創建後無法改變id即可
Map<User,Integer>map=new HashMap<>();
User user=new User(1);
System.out.println("初始hash:"+user.hashCode());
map.put(user,11);
user.setName("11");
System.out.println("賦值後的hash:"+user.hashCode());
System.out.println(map.get(user));
}
class User {
private int id;
private String name;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return id == user.id &&
Objects.equals(name, user.name);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
public User(final int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
運行結果:
初始hash:32
賦值後的hash:32
11