程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

Java 集合——Set

发布于2021-05-29 22:40     阅读(1449)     评论(0)     点赞(29)     收藏(1)


本篇章中有些地方没有描述清楚,具体详细情况参考https://blog.csdn.net/b15735105314/article/details/117233527,因为set是基础map实现的。

一、Set概念

Set容器是一个不包含重复元素的Collection,并且最多包含一个null元素,它和List容器相反,Set容器不能保证其元素的顺序。

最常用的两个Set接口的实现类是HashSet和TreeSet.

 

二、HashSet

HashSet扩展AbstractSet并且实现Set接口

HashSet使用散列表(又称哈希表)进行存储

构造方法:

HashSet()默认构造方法
HashSet(Collection c)使用collection集合进行初始化
HashSet(int capacity)指定初始数组的大小
HashSet(int capacity, float fillRatio)指定初始数组的大小和扩容因子

 

HashSet没有定义任何超过它的父类和接口提供的其他方法

散列集合没有确保其元素的顺序,因为散列处理通常不参与排序,而且每次有新的元素加入的时候,顺序也会发生改变。

散列集合不保证它的元素的顺序。元素加入散列集合的顺序并不一定是他们被迭代读出的顺序。

自定义类作为HashSet的元素的时候,规定要重写类的hashCode() 和 equals() 两个方法。

HashSet通过元素的hashCode() 和 equals() 两个方法判断元素是否相同,如果元素的hashCode()方法相同且equals()也相等,那么HashMap就认为元素是相等的。
 

总结:HashSet的内部操作的底层数据是HashMap,只是我们操作的是HashMap的Key。

  1. @Getter
  2. @AllArgsConstructor
  3. static class Student implements Comparable<Student>{
  4. private String name;
  5. private Integer age;
  6. @Override
  7. public String toString() {
  8. return "Student{" +
  9. "name='" + name + '\'' +
  10. ", age=" + age +
  11. '}';
  12. }
  13. @Override
  14. public boolean equals(Object o) {
  15. if (this == o) return true;
  16. if (o == null || getClass() != o.getClass()) return false;
  17. Student student = (Student) o;
  18. return Objects.equals(name, student.name) &&
  19. Objects.equals(age, student.age);
  20. }
  21. @Override
  22. public int hashCode() {
  23. return Objects.hash(name, age);
  24. }
  25. @Override
  26. public int compareTo(Student o) {
  27. return this.getName().compareTo(o.getName());
  28. }
  29. }

示例1:

  1. @Test
  2. public void hashSet(){
  3. Set<Student> set = new HashSet<>();
  4. Student stu1 = new Student("唐三", 25);
  5. Student stu2 = new Student("比比东", 50);
  6. Student stu3 = new Student("千道流", 130);
  7. Student stu4 = new Student("波塞西", 200);
  8. Student stu5 = new Student("唐三", 25);
  9. set.add(stu1);
  10. set.add(stu2);
  11. set.add(stu3);
  12. set.add(stu4);
  13. System.out.println(set.add(stu5));
  14. System.out.println(set);
  15. }
  16. 输出内容:
  17. false
  18. [Student{name='比比东', age=50}, Student{name='千道流', age=130}, Student{name='唐三', age=25}, Student{name='波塞西', age=200}]

上面实例中,姓名为“唐三”的student在第二次加入的时候是失败的,所以add方法返回false,HashMap在判定key相等的时候,会进行值的替换,HashSet在判定Key相等的时候,后面的值会被忽略掉。

三、TreeSet

TreeSet为使用树来进行存储的Set接口提供了一个工具,对象安升序存储,访问和检索很快

在存储了大量的需要进行快速检索的排序信息的情况下,TreeSet是一个很好的选择。

构造方法:

TreeSet()默认构造方法
TreeSet(Collection c)使用一个Collection对象进行初始化
TreeSet(Comparator comp)构造TreeSet,并传入比较对象Comparator
TreeSet(SortedSet ss) 

 

TreeSet使用Comparator的compare方法(或者元素所属类型实现Comparable接口的compareTo方法)判断元素是否相等,元素是否相等与hashCode() 和 equals() 两个方法没有任何关系,如果compare()或者compareTo()方法返回0就表示元素是相等的。

在创建TreeSet的时候,要么传入Comparator的实现类,要么元素的所属类实现Comparable的compareTo方法,二者必须选择一个;且如果二者同时满足,会选择传入的Comparator的实现类进行元素的比较。

Comparator#compare:

Comparable#compareTo:
 

总结:TreeSet的内部操作的底层数据是TreeMap,只是我们操作的是TreeMap的key。

示例2:

  1. @Test
  2. public void treeSet(){
  3. Set<Student> set = new TreeSet<>();
  4. Student stu1 = new Student("tangsan", 25);
  5. Student stu2 = new Student("bibidong", 50);
  6. Student stu3 = new Student("qiandaoliu", 130);
  7. Student stu4 = new Student("bosaixi", 200);
  8. Student stu5 = new Student("tangsan", 26);
  9. set.add(stu1);
  10. set.add(stu2);
  11. set.add(stu3);
  12. set.add(stu4);
  13. System.out.println(set.add(stu5));
  14. System.out.println(set);
  15. }
  16. 输出内容:
  17. false
  18. [Student{name='bibidong', age=50}, Student{name='bosaixi', age=200}, Student{name='qiandaoliu', age=130}, Student{name='tangsan', age=25}]

 Student实现comparable接口的compareTo时,使用的时用户姓名座对比,所以两个“tangsan”student,只有第一次的被存储。第二次存储“tangsan”时返回false。

示例3:

  1. @Test
  2. public void treeSet(){
  3. Set<Student> set = new TreeSet<>(new Comparator<Student>() {
  4. @Override
  5. public int compare(Student s1, Student s2) {
  6. if(s1.getName().compareTo(s2.getName()) > 0){
  7. return 1;
  8. } else if (s1.getName().compareTo(s2.getName()) < 0){
  9. return -1;
  10. } else {
  11. return s1.getAge().compareTo(s2.getAge());
  12. }
  13. }
  14. });
  15. Student stu1 = new Student("tangsan", 25);
  16. Student stu2 = new Student("bibidong", 50);
  17. Student stu3 = new Student("qiandaoliu", 130);
  18. Student stu4 = new Student("bosaixi", 200);
  19. Student stu5 = new Student("tangsan", 26);
  20. set.add(stu1);
  21. set.add(stu2);
  22. set.add(stu3);
  23. set.add(stu4);
  24. System.out.println(set.add(stu5));
  25. System.out.println(set);
  26. }
  27. 输出内容:
  28. [Student{name='bibidong', age=50}, Student{name='bosaixi', age=200}, Student{name='qiandaoliu', age=130}, Student{name='tangsan', age=25}, Student{name='tangsan', age=26}]

上面示例中传入了Comparator对象,如果传入Comparator对象,那么就不会再使用自然顺序进行排序,Comparator在实现的时候,先使用姓名进行对比,在姓名相同的时候,使用年龄进行对比。所以上面的示例中两个“tangsan”都成功存储,而且25岁的在前,26岁的在后。

四、LinkedHashSet

LinkedHashSet是基于HashSet实现的,所以特性参考HashSet就行,唯一的区别就是LinkedHashSet可以保证输入顺序和输出顺序保持一致。

示例:

  1. @Test
  2. public void linkedHashSet(){
  3. Set<Student> set = new LinkedHashSet<>();
  4. Student stu1 = new Student("唐三", 25);
  5. Student stu2 = new Student("比比东", 50);
  6. Student stu3 = new Student("千道流", 130);
  7. Student stu4 = new Student("波塞西", 200);
  8. Student stu5 = new Student("唐三", 25);
  9. set.add(stu1);
  10. set.add(stu2);
  11. set.add(stu3);
  12. set.add(stu4);
  13. System.out.println(set.add(stu5));
  14. System.out.println(set);
  15. }
  16. 输出内容:
  17. false
  18. [Student{name='唐三', age=25}, Student{name='比比东', age=50}, Student{name='千道流', age=130}, Student{name='波塞西', age=200}]

 

原文链接:https://blog.csdn.net/b15735105314/article/details/117248630



所属网站分类: 技术文章 > 博客

作者:以天使的名义

链接:http://www.javaheidong.com/blog/article/207646/320f5f7bb83d47ac98d6/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

29 0
收藏该文
已收藏

评论内容:(最多支持255个字符)