可变对象:指创建后自身的哈希值可能被改变的对象。
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