分析 HashSet 和 TreeSet 分别如何实现去重的

  分析 HashSet 和 TreeSet 分别如何实现去重的:

 

(1)HashSet 的去重机制:hashCode() + equals()。底层先通过存入对象,进行运算得到一个 hash 值,通过 hash 值得到对应的索引,如果发现 table 索引所在的位置,没有数据,就直接存放;如果有数据,就进行 equals 遍历比较,比较后不相同,就加入,否则,不加入。

(2)HashMap 的去重机制:如果传入了一个 Comparator 匿名对象,就使用实现的 compare 去重。如果方法返回0,就认为是相同的元素,不添加键,把对应的值覆盖;如果没有传入 Comparator 匿名对象,则以所添加的对象实现的 Compareable 接口的 CompareTo 去重。

 


 

附1:三种方法的对比

 

① equals

这个方法只能用作对象之间的比较,比较是否相等(=/ !=),而不能比较出谁大谁小(>,<,=)。

如果没有重写equals方法,那会自动调用object类的equals方法,即比较地址。

重写类的equals方法时,要同时把hashCode方法也重写。

②  基于 Comparble 接口类的比较

写在类的里面,参数是所要比较的类。比较本类和所传入的类。

对用用户自定义类型,如果要想按照大小与方式进行比较时:在定义类时,实现Comparble接口即可,然后在类中重写 compareTo 方法。这种方式可以实现存在排序的大小比较,但是只能根据一个比较准则来进行比较。

class Student implements Comparable<Student> {
    public int age;
    public String name;
    @Override
    public int compareTo(Student o) {  // 写在类的里面,比较的是本类和传入的类
        return this.age - o.age;
    }
}

③ 基于 Comparator 接口类的比较

写在类的外部,参数是两个比较的对象。

重写 Comparetor 里的 compare 方法即可。可以每个准则对应生成一个类、实现 Comparator 接口,然后重写 compare 方法。

class Student {
    public int age;
    public String name;
    }
// 写在类的外部,参数是两个比较的对象
//年龄比较器
class AgeComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.age - o2.age;
    }
}
//姓名比较器
class NameComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name);//直接调用引用类型String的比较方法
    }
}

 


 

 

附2:代码分析题:下面代码运行是否抛出异常,从源码层面说明原因。

TreeSet treeSet = new TreeSet();
treeSet.add(new Person());

class Person{}

分析:add 方法,因为 TreeSet() 构造器没有传入 Comparator 接口的匿名内部类,所以在底层会实现 Comparable<? super K> k = (Comparable<? super K>) key; 即把 Person 类转成  Compareable 类型,而 Person 类并未实现该接口。因此 add 语句会报错:ClassCastException。

posted @ 2024-08-27 20:13  JuneFall  阅读(12)  评论(0编辑  收藏  举报