java 入土--集合详解( 二 )

SetSet 接口也是单例的,是无序的,增加和取出顺序是不确定的,无索引不可重复,null 最多有一个 。继承自 Collection 接口,Set 的方法与 List 的方法相差不大,但不能用索引的方式遍历 。
HashSetHashSet 实现 Set 接口,其底层是 HashMap,由于 HashMap 的底层是数组+链表+红黑树,所以 HashSet 的底层就是数组+链表+红黑树,存储时,底层通过 equles()和 hash()方法来确定存储位置,所以存入与取出的顺序不一致 。

java 入土--集合详解

文章插图
HashSet 的初始大小是 16 长度大小的数组,当数组的容量达到 16 的 0.75 倍时,会进行提前扩容,也就是数组在满足 12 时,会进行扩容,其扩容倍数为 2 倍 。
注:当数组长度大于 64,同时链表长度大于 8 时,hashSet 变为红黑树存储,优化存储结构 。
要注意重写 hashCode 与 equlse 方法才能使不同对象的相同内容实现不重复 。
LinkedHashSet父类是 HashSet,底层是 LinkedHashMap,维护了一个数组+双向链表 , 也是以 hsash 值来确定位置 。存储结构是双向链表 , 所以是有序的,不允许有双向链表 。
  • 扩容机制
    • 第一次时,数组 table 扩容到 16,底层是存储在 LinkedHashMap$Entry 对象节点上 , 数组是 HashMap$Node[],在数组中存放 LinkedHashMap$Entry 对象 。
TreeSet底层是 TreeMap , 可以进行排序,当我们使用无参构造器,创建 TreeSet 时,仍然是无序的.当我们需要按照某种方式进行排序时,需要使用 TreeSet 提供的一个构造器 , 可以传入一个比较器[匿名内部类]并指定排序规则
//具体的比较规则还需根据实际进行重写,这里举一个例子 。TreeSet<Object> objects = new TreeSet<>(new Comparator<Object>() {@Overridepublic int compare(Object o1, Object o2) {return o1.toString().compareTo(o2.toString());}});TreeSet 接口间接实现了 Set 接口,是一个有序的集合,它的作用是提供有序的 Set 集合
TreeSet 的特点
  1. 元素有序:按照构造方法进行排序
    1. TreeSet()根据元素的自然排序进行排序
    2. TreeSet(Comparator comparator):根据指定的比较器进行排序,自然排序需要在类中实现 comparator 接口
      java 入土--集合详解

      文章插图
  2. 没有索引,不能用普通 for 循环遍历
  3. 继承 Set 集合,无重复元素
TreeSet<Integer> ts = new TreeSet<Integer>();//自然排序ts.add(10);ts.add(20);ts.add(4);for (Integer i : ts) {System.out.println(i);//输出4,10,20}
java 入土--集合详解

文章插图
通过指定比较器进行排序
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {//o1是o2是的下一个int num = o1.getAge() - o2.getAge();int num2 = num == 0 ? o1.getName().compareTo(o2.getName()) : num;return num2;}});//创建对象Student s1 = new Student("maoyaning", 32);Student s2 = new Student("asdfds", 53);Student s3 = new Student("khljn", 24);Student s4 = new Student("sdfwfds",24);//添加集合元素ts.add(s1);ts.add(s2);ts.add(s3);ts.add(s4);for (Student s : ts) {System.out.println(s.getName() + " " + s.getAge());}Set 两种循环遍历:由于 Set 集合的底层,所以无法用下标遍历,因此只能用增强 for 和 iterator 进行遍历
  1. 增强 for
for (String str : set) {System.out.println(str);}
  1. 迭代器
Set set = new HashSet();Iterator it = set.iterator();while (it.hasNext()) {String str = it.next();System.out.println(str);}Map 接口Map<K,V>,是一个接口,将键映射到值,不能包含重复的键 , 每个键只能映射一个值 。
java 入土--集合详解

文章插图
Map 接口用于存储具有映射关系的数据,key-value 。
底层:
  • 在创建 Map 集合时,Map 的底层会创建 EntrySet 集合,用于存放 Entry 对象,而一个 Entry 对象具有 key 和 value,同时创建 Set 数组指向 key,创建 collection 对象指向 value,取出时 , 实际上是调用 set 和 collection 数组的地址进行调用 , 从而提高遍历效率 。
在进行 map 元素添加时,map.put()方法在底层上是通过 hashcode 与 equals 方法进行比较,当 key 相同时 , 会进行替换 。要注意的是,HashSet 的底层也是 HashMap,也是以键值对的形式进行存储的,只不过在进行录入时,把 value 值设置为一个常数,所以在 HashSet 中 , 不能存储相同的值(会进行覆盖) 。而在 Map 中 , 可以存储相同的 value 值,但是 Key 不能重复,也就是说在 Map 中,key 可以有 null,但是只能有一个 , value 可以有多个 null 。

推荐阅读