不要用可变类型做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的键还是选用不可变的好,如果可变的话勉强也能用,但会造成数据冗余和别扭,还可能有我没发现的隐患。

posted @ 2024-02-28 18:21  让时间变成力量  阅读(7)  评论(0)    收藏  举报