分析 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。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)