不要用可变类型做HashMap和HashSet键值
1 不要用可变类型做HashMap和HashSet键值
这是我在学 “为什么String类要使用final修饰”发现的。
在最初看到这个话的时候,我想了想,如果是一个引用类型做HashSet的键的类型,再重写它的 hashCode方法和equals方法不就好了吗,于是我敲了一下,发现这是两回事。
结论:当使用引用类型作为HashSet的键时,除非该引用类型的属性不可被修改,那么该引用类型仍然会破坏HashSet的不重复性。
// User类
@Data
@ToString
public class User1 {
private String name;
private Integer age;
public User1(String name, Integer age){
this.name=name;
this.age=age;
}
public User1(){
}
@Override
public int hashCode() {
int result= name!=null?name.hashCode():0;
result=result*31+age;
return result;
}
@Override
public boolean equals(Object obj) {
System.out.println("User equals.....");
if(this==obj) return true;
if(obj==null || getClass()!=obj.getClass()) return false;
User1 user=(User1)obj;
if(age != user.age) return false;
return name!=null ? name.equals(user.name) : user.name == null;
}
}
// 测试代码
public class MyTest{
@Test
public void test1() {
HashSet<User1> users = new HashSet<>();
User1 user1 = new User1("yfm", 10);
User1 user2 = new User1("yfm", 20);
users.add(user1);
users.add(user2);
users.forEach(System.out::println);
user2.setAge(10);
System.out.println("=========");
users.forEach(System.out::println);
}
}
/*输出结果
User1(name=yfm, age=10)
User1(name=yfm, age=20)
=========
User1(name=yfm, age=10)
User1(name=yfm, age=10)
*/
应该还是能添加new User1("yfm", 20)的,添加后再删除new User1("yfm", 20)则会删除新增的这一个,删除new User1("yfm", 10)则会删除user1(纯根据HashMap的底层逻辑推断而出的,未测试)
再总结:总而言之,HashSet的键还是选用不可变的好,如果可变的话勉强也能用,但会造成数据冗余和别扭,还可能有我没发现的隐患。

浙公网安备 33010602011771号