Java集合框架

#Java集合框架


##一, 集合体系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nARBLNmh-1618037485320)(D:\desktop\CommonWork\2021笔记文件\img\集合img\集合体系.png)]

##二,List Set Map 的区别

  1. List 有序的可重复的

    1. ArrayList底层使用 Object[]
      1. 查询快增删慢 线程不安全 效率高
        1. 支持随机访问
          1. 使用RandomAccess标识
        2. 并发修改异常
      2. 扩容机制
        1. 每次扩容为1.5倍
      3. 遍历异常
        1. 使用foreach和迭代器Iterator遍历是不能添加和修改
      4. ArrayList实现了Cloneable方法和Serializable
    2. Vector 底层也是object[]
      1. 方法级别线程安全 效率低
      2. 可使用CopyOnWriteArrayList替代
    3. LinkedList 底层使用链表
      1. 查询慢增删快 线程不安全 效率高
      2. 双向链表 jdk1.6之前循环链表 1.7取消了循环链表
    4. ####List如何遍历

    5. //对象遍历
          @Test
          public void Test02(){
              ArrayList<student> list02 = new ArrayList<>();
              student s1 = new student("小明",15);
              student s2 = new student("小红",12);
              student s3 = new student("小芳",15);
      
              list02.add(s1);
              list02.add(s2);
              list02.add(s3);
      
              System.out.println(list02);
      
              for (int i = 0; i < list02.size(); i++) {
          		System.out.println(list02.get(i).getName()
                  	+""+","+list02.get(i).getAge());
              }
              Iterator<student> iterator = list02.iterator();
              while(iterator.hasNext()){
                  student s = iterator.next();
                  System.out.println(s.getName()+""+s.getAge());
              }
              for (student student : list02) {
         			System.out.println(student.getName()
                  	+student.getAge());
              }
          }
      
  2. Set 无序的不可重复的

    1. HashSet
      1. 底层使用HashMap
      2. 如何验重
        1. 首先添加元素,根据hash码来找存储位置
        2. 如何存储位置有元素,hash码有重复
        3. equals() 比较 如何相同 则将元素添加到链表尾
    2. LinkedHashSet
    3. TreeSet
      1. 底层TreeMap使用红黑树(自平衡二叉树)
  3. Map 通过key-value键值对存储一一对应,key无序不可重复,value可以重复。

    1. HashMap
      1. 底层使用数组+链表
        1. 可以存储null 但是只能有一个null
        2. 初始容量是 16 每次扩容 2 的幂次方 。
        3. JDK1.8 之后当链表长度大于 8 时就转换为红黑树 ( 当数组长度小于64,先进行数组扩容)
        4. 相比较与HashSet 使用扰动函数 (n - 1) & hash 减少hash碰撞
          1. (n - 1) & hash 也是由于这个所以 HashMap 每次扩容都需要2的幂次方
        5. HashMap 死循环
          1. 当并发环境中其不是线程安全 ,Rehash 就会出现循环链表。所以建议使用ConcurrentHashMap
    2. TreeMap
      1. 底层使用红黑树来实现有序和不可重复 。

      2. 不能添加null

      3. 添加的元素必须是可以比较的,以实现有序性。

      4.      ┌───┐
             │Map│
             └───┘
               ▲
          ┌────┴─────┐
          │          │
        ┌───────┐ ┌─────────┐
        │HashMap│ │SortedMap│
        └───────┘ └─────────┘
                       ▲
                       │
                  ┌─────────┐
                  │ TreeMap │
                  └─────────┘
        
      5. 注意到Person类并未覆写equals()hashCode(),因为TreeMap不使用equals()hashCode()

      6. 特点

        1. SortedMap在遍历时严格按照Key的顺序遍历,最常用的实现类是TreeMap

          作为SortedMap的Key必须实现Comparable接口,或者传入Comparator

          要严格按照compare()规范实现比较逻辑,否则,TreeMap将不能正常工作。

    3. Hashtable
      1. 线程安全方法级别的synchronized
      2. 建议使用ConcurrentHashMap
      3. 初试容量 11 。 2n+1 倍扩容
      4. 不能添加null
    4. Map遍历方式
      1. public static void main(String[] args) {
                 Map<Integer, String> map = new HashMap<Integer, String>();
                map.put(1, "a");
                map.put(2, "b");
                map.put(3, "ab");
                map.put(4, "ab");
                map.put(4, "ab");// 和上面相同 , 会自己筛选
                System.out.println(map.size());
        
                System.out.println("第一种:通过Map.keySet遍历key和value:");
                for (Integer in : map.keySet()) {
                    //map.keySet()返回的是所有key的值
                    String str = map.get(in);//得到每个key多对用value的值
                    System.out.println(in + "     " + str);
                }
        
        
                System.out.println("第二种:通过Map.entrySet使用iterator遍历key和value:");
                Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();
                while (it.hasNext()) {
                    Map.Entry<Integer, String> entry = it.next();
                    System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
                }
        
                // 第三种:推荐,尤其是容量大时
                System.out.println("第三种:通过Map.entrySet遍历key和value");
                for (Map.Entry<Integer, String> entry : map.entrySet()) {
                    //Map.entry<Integer,String> 映射项(键-值对)  有几个方法:用上面的名字entry
                    //entry.getKey() ;entry.getValue(); entry.setValue();
                    //map.entrySet()  返回此映射中包含的映射关系的 Set视图。
                    System.out.println("key= " + entry.getKey() + " and value= "
                            + entry.getValue());
                }
        
                System.out.println("第四种:通过Map.values()遍历所有的value,但不能遍历key");
                for (String v : map.values()) {
                    System.out.println("value= " + v);
                }
        
            }
        
      2. 使用那种呢

        1. 所以通过字节码来看,使用 EntrySetKeySet 代码差别不是很大,并不像网上说的那样 KeySet 的性能远不如 EntrySet,因此从性能的角度来说 EntrySetKeySet 几乎是相近的,但从代码的优雅型和可读性来说,还是推荐使用 EntrySet
      3. 修改

        1. 我们不能在遍历中使用集合 map.remove() 来删除数据,这是非安全的操作方式,但我们可以使用迭代器的 iterator.remove() 的方法来删除数据,这是安全的删除集合的方式。同样的我们也可以使用 Lambda 中的 removeIf 来提前删除数据,或者是使用 Stream 中的 filter 过滤掉要删除的数据进行循环,这样都是安全的,当然我们也可以在 for 循环前删除数据在遍历也是线程安全的。

        2. // 根据 map 中的 key 去判断删除
          map.keySet().removeIf(key -> key == 1);
          map.forEach((key, value) -> {
              System.out.println("show:" + key);
          });
          
        3. Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();
          while (iterator.hasNext()) {
              Map.Entry<Integer, String> entry = iterator.next();
              if (entry.getKey() == 1) {
                  // 删除
                  System.out.println("del:" + entry.getKey());
                  iterator.remove();
              } else {
                  System.out.println("show:" + entry.getKey());
              }
          }
          

三,comparableComparator

  1. 实现对对象的自定义排序

    1. comparable

    2. public  class Person implements Comparable<Person> {
          private String name;
          private int age;
      
          public Person(String name, int age) {
              super();
              this.name = name;
              this.age = age;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public int getAge() {
              return age;
          }
      
          public void setAge(int age) {
              this.age = age;
          }
      
          /**
           * T重写compareTo方法实现按年龄来排序
           */
          @Override
          public int compareTo(Person o) {
              if (this.age > o.getAge()) {
                  return 1;
              }
              if (this.age < o.getAge()) {
                  return -1;
              }
              return 0;
          }
      }
      
    3. Comparator

    4. ArrayList<Integer> arrayList = new ArrayList<Integer>();
              arrayList.add(-1);
              arrayList.add(3);
              arrayList.add(3);
              arrayList.add(-5);
              arrayList.add(7);
              arrayList.add(4);
              arrayList.add(-9);
              arrayList.add(-7);
              System.out.println("原始数组:");
              System.out.println(arrayList);
              // void reverse(List list):反转
              Collections.reverse(arrayList);
              System.out.println("Collections.reverse(arrayList):");
              System.out.println(arrayList);
      
              // void sort(List list),按自然排序的升序排序
              Collections.sort(arrayList);
              System.out.println("Collections.sort(arrayList):");
              System.out.println(arrayList);
              // 定制排序的用法
              Collections.sort(arrayList, new Comparator<Integer>() {
      
                  @Override
                  public int compare(Integer o1, Integer o2) {
                      return o2.compareTo(o1);
                  }
              });
              System.out.println("定制排序后:");
              System.out.println(arrayList);
      
    5. 说明

      1. 定制排序也可以另外写一个类继承ComparaTo 创建排序方式
      2. 使用上可以直接在创ArrayList时候直接传入ComparaTo
      3. 另外如何遇到TreeSet TreeMap 有序集合,必须将自己的Bean对象实现comparable或者ComparaTo实现对象可比较。
  2. 无序性和不可重复性

    1. 无序性
      1. 存储元素不在根据添加顺序而是根据自身的hash值
    2. 不可重复性
      1. 当元素的equals()方法,返回false,则需要同时重写equals()hashcode()方法。

三,线程安全的集合接口

  1. 线程安全的接口Concurrent

  2. 实现类 ConcurrentHashMap

    1. 分段的数组+链表

    2. 原理

      1. 首先将数据分为一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问。
    3. 实现方式

      1. ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成。

        Segment 实现了 ReentrantLock,所以 Segment 是一种可重入锁,扮演锁的角色。HashEntry 用于存储键值对数据。

四, Collections 工具类

  1. 常用方法

    1. 排序

      1. void reverse(List list)//反转
        void shuffle(List list)//随机排序
        void sort(List list)//按自然排序的升序排序
        void sort(List list, Comparator c)//定制排序,由Comparator控制排序逻辑
        void swap(List list, int i , int j)//交换两个索引位置的元素
        void rotate(List list, int distance)//旋转。当distance为正数时,将list后distance个元素整体移到前面。
        //当distance为负数时,将 list的前distance个元素整体移到后面
        
    2. 查找,替换操作

      1. int binarySearch(List list, Object key)//对List进行二分查找,返回索引,注意List必须是有序的
        int max(Collection coll)//根据元素的自然顺序,返回最大的元素。 类比int min(Collection coll)
        int max(Collection coll, Comparator c)//根据定制排序,返回最大元素,排序规则由Comparatator类控制。类比int min(Collection coll, Comparator c)
        void fill(List list, Object obj)//用指定的元素代替指定list中的所有元素。
        int frequency(Collection c, Object o)//统计元素出现次数
        int indexOfSubList(List list, List target)//统计target在list中第一次出现的索引,找不到则返回-1,类比int lastIndexOfSubList(List source, list target).
        boolean replaceAll(List list, Object oldVal, Object newVal), 用新元素替换旧元素
        
    3. 同步控制(不推荐,需要线程安全的集合类型时请考虑使用 JUC 包下的并发集合)

##五,集合脑图

集合总结脑图

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值