Java-Set 雨点打透心脏的1/2处 2024-03-26 13:12 14阅读 0赞 ## 一、Set ## > Set集合是Collection集合的子接口,该集合中不能有重复元素!! > Set集合提供的方法签名,与父接口Collection的方法完全一致!! 即没有关于下标操作的方法 > Set接口,它有两个常用的子实现类HashSet,TreeSet ## 二、HashSet ## > HashSet实现了Set接口,底层是hash表(实际上底层是HashMap) > 该类不允许重复元素,不保证迭代顺序,即无序(插入顺序和遍历顺序不一致) ### **2.1 方法演示** ### > **构造方法** > HashSet() 构造一个新的空 set,其底层 HashMap 实例的默认 **初始容量是 16**, **加载因子是 0.75**。 > HashSet(Collection<? extends E> c)构造一个包含指定 collection 中的元素的新 set > HashSet(int initialCapacity) 构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和默认的加载因子(0.75)。 > HashSet(int initialCapacity, float loadFactor) 构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和指定的加载因子。 > **方法** > HashSet类中的方法与父接口Set接口中的方法一致,即又跟Collection接口中方法一致 public static void main(String[] args) { // 创建HashSet集合 HashSet<Integer> set = new HashSet<>( ); // 放入元素 boolean r1 = set.add(221); System.out.println(r1 ); boolean r2 = set.add(221); System.out.println(r2 ); set.add(111); set.add(111); set.add(44); set.add(23); // 遍历(for + Iterator) for(Integer i: set) { System.out.println(i ); } // 总结: 顺序问题+ 重复问题 // 无序即 插入顺序和迭代顺序不一致 // 不允许重复! Iterator<Integer> iterator = set.iterator( ); while(iterator.hasNext()) { Integer integer = iterator.next( ); System.out.println(integer ); } // 演示其他方法(移除,判断,大小等等) System.out.println(set.size() ); System.out.println(set.isEmpty( )); set.clear(); System.out.println(set.size() ); System.out.println(set.isEmpty( )); HashSet<Integer> set2 = new HashSet<>( ); set2.add(111); // 移除全部指定元素 System.out.println(set.removeAll(set2)); System.out.println(set ); } ### **2.2 扩容机制** ### > HashSet底层是Hash表,其实是HashMap. > **默认初始容量16,加载因子0.75 ---> 扩容的阈值= 容量 \* 因子 = 16 \* 0.75 = 12即超过12个元素时就要触发扩容,扩容成原来的2倍** > (ps: 初始容量和加载因子是可以通过构造方法创建时修改的...) ### **2.3 去重原理(先hashcode再equals)** ### > 调用add(E e)方法时,会在底层调用元素e的hashcode方法来获得对象的地址值 > 如果地址值不一样,直接存储 > 如果地址值一样时,会再调用元素的equals方法判断元素的内容是否一样 > 如果equals为false,那么存储 但是如果equals判断值为true,那么去重 (PS:**重写hashcode时**,要**把返回值设为一致**,这样地址一样了才能去重,否则每次new的对象都是不同的地址,hash地址不同则不执行后面的equals了。 同一个地址存储多个对象,是因为存储在“桶”中) > 以后只需要使用工具生成hashcode和equals就可以再HashSet中去重! > public static void main(String[] args) { HashSet<Integer> set = new HashSet<>( ); set.add(1); set.add(2); set.add(3); set.add(1); System.out.println(set ); // 创建几个学生,放入set集合 // 设想属性一样的学生会去重 HashSet<Student> stuSet = new HashSet<>( ); stuSet.add(new Student(18,"zs")); stuSet.add(new Student(19,"ls")); stuSet.add(new Student(19,"ls")); stuSet.add(new Student(20,"ww")); System.out.println(stuSet ); } ## 三、LinkedHashSet ## > LinkedHashSet 既有Set的去重的特性,又有Linked结构有序的特性,即存储在LinkedHashSet 中的元素既不允许重复,又能保证迭代顺序 LinkedHashSet<Integer> lhs = new LinkedHashSet<>( ); ## 四、TreeSet ## > TreeSet是基于 TreeMap 的 NavigableSet 的实现.可以使用元素的 自然顺序对元素进行排序或者根据创建 TreeSet 时提供的 Comparator 进行排序,具体取决于使用的构造方法 > 即TreeSet会对存储的元素排序,当然也会去重! ### **4.1 方法演示** ### > **构造方法** > TreeSet()构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。 > TreeSet(Comparator<? super E> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。 > **方法** > 有常规的集合的方法(add,remove,Iterator,size等等),还有一些基于树结构能排序的特性才有的特殊方法,例如范围取值的(ceiling(),floor(),lower(),higher(),首尾取值(),first(),last()...)等操作 TreeSet<Integer> set = new TreeSet<>( ); set.add(44); set.add(221); set.add(221); set.add(23); // 发现: 会排序(默认是升序),不能存储重复元素 System.out.println(set ); for(Integeri : set) { System.out.println(i ); } // 获得第一个(排序后) System.out.println("first: "+set.first( )); // 获得最后一个(排序后) System.out.println("last: "+set.last() ); System.out.println(set ); // 获取并移除第一个(排序后) System.out.println("第1个"+set.pollFirst()); // 获取并移除最后一个(排序后) System.out.println("最hou1个"+set.pollLast()); System.out.println(set ); // floor 返回此 set 中 小于等于 给定元素的最大元素 // ceiling 返回此 set 中 大于等于 给定元素的最小元素 // 返回 小于 参数 的最大内容 System.out.println(ts.lower(33)); System.out.println(ts); // 返回 大于 参数 的最大内容 System.out.println(ts.higher(34)); System.out.println(ts); // 范围取值 System.out.println(set.lower(100)); } ### **4.2 去重排序原理(**通过Compareable接口的compareto方法来保证的**)** ### > 前提知识: TreeSet底层是TreeMap,TreeMap是红黑树,是一种平衡二叉树(AVL) **eg**:新建User类(age,name),创建TreeSet集合,创建多个User对象,将user对象存入TreeSet集合,实现去重排序,1) 年龄和姓名一致则去重 2) 按照年龄从小到大排序 TreeSet<User> set= new TreeSet<>( ); set.add(newUser(18,"丫丫")); // **运行报错ClassCastException 无法转成Comparable接口** > Comparable接口,强行对实现它的每个类的对象进行整体排序,这种排序被称为类的 *自然排序*.实现这个接口,需要重写comparTo方法,该方法返回值决定了是升序,降序还是去重! > 该comparTo(T t)方法运行时 , this指代当前正在调用该方法的对象,参数T就是之前已经存在的元素. > 返回值 0,意味着此元素(正在存储的元素)和之前的 元素相同,即 不存储,则去重 > 返回值 正整数,意味着此元素 大于 之前的元素, 放在该节点的**右边** > 返回值 负整数,意味着此元素 小于 之前的元素, 放在该节点的**左边** > 最后都存储完毕时,取值时 采用中序遍历(从根节点开始按照左,中,右的顺序读取) ## 五、总结 ## HashSet 方法与父Collection接口中方法一致 需要记住: HashSet底层(HashMap),扩容,去重原理 LinkedHashSet 了解 TreeSet底层的树结构能了解就行,只需要指定要想去除排序,必须要实现接口重写方法,返回0去重,返回正负如何如何: <table style=""> <tbody> <tr> <td style="width:341px;vertical-align:top;height:51px;"><p style="text-align:left;"><span style="font-size:13pt;"><span style="background-color:#FBF5B3;">// 0 相同</span></span></p><p style="text-align:left;"><span style="font-size:13pt;"><span style="background-color:#FBF5B3;">// return 0;</span></span></p><p style="text-align:left;"><span style="font-size:13pt;"><span style="background-color:#FBF5B3;">// 正整数 此元素大于之前的元素</span></span></p><p style="text-align:left;"><span style="font-size:13pt;"><span style="background-color:#FBF5B3;">// return 1;</span></span></p><p style="text-align:left;"><span style="font-size:13pt;"><span style="background-color:#FBF5B3;">// 负整数 此元素小于之前的元素</span></span></p><p style="text-align:left;"><span style="font-size:13pt;"><span style="background-color:#FBF5B3;"> return -1;</span></span></p></td> </tr> </tbody> </table>
相关 JavaSet的源码分析 Java中,set能保证列表中元素唯一,map就是用来key-value用的东西。 先看Set。 首先Set是个接口,最常见的实现有HashSet,LinkedHashSe 叁歲伎倆/ 2022年06月13日 00:48/ 0 赞/ 252 阅读
还没有评论,来说两句吧...