思维导图06----Java集合

Java集合----思维导图

下载地址: https://download.csdn.net/download/q863672107/20016476

集合内容比较多

在这里插入图片描述


以下是自动转换的MakeDown文本


集合

集合框架

单列集合

  • Collection接口

    • List接口

      • 实现类

        • ArrayList类
          主要实现类

          • 数组实现的

            • 查询快, 增删慢
        • LinkedList类

          • 双向链表实现的

            • 增删快, 查询慢
        • Vector类
          古老实现类1.0

          • 同ArrayList

            • 线程安全的
              效率低
      • 特点

        • 有索引

          • 可以存储重复元素

            • 存取有序
    • Set接口

      • 特点

        • 无索引

          • 不可存储重复元素

            • 存取无序
      • 实现类

        • HashSet类

          • 底层是HashMap

            • 哈希表(数组+链表+红黑树(JDK8))
        • LinkedHashSet类

          • 底层LinkedHashMap

            • 哈希表(数组+链表/红黑树(JDK8))+双向指针

            • 不同于其他Set集合, LinkedHashMap底层在哈希表基础上, 每个节点还保存了对添加的前一个和后一个节点的引用, 保证存取顺序

              • 遍历效率高
        • TreeSet类

          • 底层TreeMap

            • 红黑树

              • 一般用于排序
                不能为null

                • 存储的元素必须为同一个类型
                • 存储的key元素是Comparable接口实现类对象
                • 存储的元素按compareTo()/compare()方法比较, 不能重复
                • 或者在new TreeSet(Comparator c)时传入一个Comparator接口的对象(重写compare方法)
        • 线程安全

          • Collections.synchronizedSet(new HashSet<>())
          • 使用JUC包里面的CopyOnWriteArraySet

双列集合

  • Map接口

    • 特点

      • key-value对

        • key值不可重复
    • HashMap类

      • 哈希表(数组+链表+红黑树(JDK8))
    • LinkesHashMap类

      • 哈希表+双向指针(保证迭代顺序)
        存取有序, 遍历效率高
    • TreeMap类

      • 红黑树

        • 可根据key值排序
          key值不能为null

          • 存储的key值必须为同一个类型
          • 存储的key元素是Comparable接口实现类对象
          • 存储的key按compareTo()/compare()方法比较, 不能重复
          • 或者在new TreeMap(Comparator c)时传入一个Comparator接口的对象(重写compare方法)
    • Hashtable类
      古老实现类1.0

      • 同HashMap

        • 线程安全
          效率低
      • key跟value不能存储null值

Collection接口

方法

  • 添加

    • add(Object obj)
    • addAll(Collection c)
  • 获取有效元素个数

    • int size()
  • 清空集合

    • void clear()
  • 是否为空

    • boolean isEmpty()
  • 是否包含

    • boolean contains(Object obj)

      • 调用元素的equals方法判断是否为同一个对象
    • boolean containsAll(Collection c)

      • 也是调用元素的equals方法比较, 拿两个集合的元素挨个比较
  • 删除

    • boolean remove(Object obj)

      • 调用元素的equals方法找到要删除的第一个元素
    • boolean removeAll(Collection c)

      • 取当前集合与c的差集, 修改当前集合
  • 取两个集合交集

    • boolaen retainAll(Collection c)

      • 修改当前集合, 不影响c
  • 是否相等

    • boolean equals(Object obj)

      • 对List集合, 元素相同, 顺序一致 返回true
      • 对Set集合, 元素相同, 顺序不一致, 返回true
  • 转成对象数组

    • Object[] toArray()
  • 获取哈希值

    • hashCode()
  • 遍历

    • iterator()

      • 返回迭代器对象

Collections工具类

常用方法

  • 添加多个元素

    • static boolean addAll(Collection c, T… elements)
  • 通过多个元素创建ArrayList

    • static List asList(T… a)
  • 极值(max为例)

    • static T max(Collection coll)
    • static Object max(Collection coll, Comparator c)
  • 统计

    • int frequency(Collection coll, Object obj)
  • 批量替换

    • static boolean replaceAll(List list, T oldVal, T newVal)
  • 拷贝数组

    • static void copy(List dest, List src)

      • 如果dest.size()<src.size(), 会报异常
        还是少用吧

        List dest = new ArrayList(src.size());
        Collections.copy(dest, src);//会报异常, 想想为什么

        List dest = Arrays.asList(new Object[src.size()]);
        Collections.copy(dest, src);//不会报异常

  • 排序

    • static void sort(List list)

      • 自然排序
    • static void sort(List list, Comparator c)

      • 定制排序
  • 随机洗牌

    • static void shuffle(List list)
  • 反转

    • static void reverse(List list)
  • 交换元素

    • static void swap(Object[] x, int a, int b)

同步控制

Collections常用方法: 同步控制
Collections类中提供了多个synchronizedXxx()方法, 可将执行集合包装成线程同步的集合, 从而将解决多线程并发访问集合时的线程安全问题

如将ArrayList , HashMap转换为线程安全的

  • static Collection synchronizedCollection(Collection c)
  • static List synchronizedList(List list)
  • static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
  • static Set synchronizedSet(Set s)
  • static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)
  • static SortedSet synchronizedSortedSet(SortedSet s)

遍历集合

Iterator接口

用于Collection集合

Iterator对象称为迭代器(设计模式的一种), 主要用于遍历集合中的元素。
GOF给迭代器模式的定义为: 提供一种方法访问一种容器(container)对象中各个元素, 而又不需暴露该对象的内部细节。迭代器模式, 就是为容器而生。

Collection接口继承了Iteraor接口, 该接口有一个iterator()方法, 用以返回一个实现了Iterator接口的对象

Iterator仅用于遍历集合, Iterator本身并不提供承装对象的能力, 如果需要创建Iterator对象, 则必须有一个被迭代的集合。

  • 通过Collecction接口的iterator()方法返回Iterator对象, 迭代器不作为容器

    集合对象每次调用iterator()方法都得到一个全新的迭代器对象, 默认游标都在集合第一个元素之前。

    • 每次调用返回的是新的迭代器对象
  • 方法

    • boolean hasNext()

      • 判断是否还有下一个元素

        • 指针到达集合末尾, 则返回false
    • E next()

      • ①指针后移 ②将移动后指针位置上的元素返回

        • 指针初始化位置在第一个元素前
    • default void remove()

      • 迭代器可以在遍历过程中删除集合元素,
        注意: 这是迭代器的方法, 不同于集合的remove()

        如果还未调用next()方法, 或在上一次调用next()之后已经调用过一次remove(), 再重复调用, 会报IllegalStateException

  • 代码

    Iterator iterator = list.iterator();
    while (iterator.hasNext()){
    System.out.println(iterator.next());
    }

foreach(JDK5)(推荐)

用于Collection集合/数组

JDK5提供了foreach循环迭代访问Collection和数组
遍历操作不需要获取Collection或数组的长度, 无需使用索引访问元素。
遍历集合的底层调用Iterator完成操作
foreach还可以用来遍历数组

  • for(Object obj : coll){ }

    • 底层仍然调用了迭代器

Consumor接口

Collection/Map/数组都可使用

  • coll.foreach(new Consumer() {@Override
    public void accept(Object o) { }});

  • coll.foreach((obj)->{ });

    • lambda表达式
  • coll.foreach(System.out::println)

Stream

Stream 中文称为 “流”,通过将集合转换为这么一种叫做 “流” 的元素序列,通过声明性方式,能够对集合中的每个元素进行一系列并行或串行的流水线操作。

换句话说,你只需要告诉流你的要求,流便会在背后自行根据要求对元素进行处理, 并返回结果。

数据源–>流–>中间操作 * n -->中间操作–>终止操作

实例化

  • 串行流

    • Collection#default Stream stream()
  • 并行流

    • Collection#default Stream parallelStream()

      • 性能高, 不能保证执行顺序

中间操作

凡是返回值为Stream的都是中间操作
中间操作是惰性操作, 只有遇碰到终止操作才会执行

  • 无状态(stateless)
    线程安全

    该操作的数据不受上一步操作的影响

    • 过滤

      • Stream filter(Predicate<? super T> predicate)

        • 代码

          Stream stream = list.stream();
          Stream integerStream = stream.filter(new Predicate() {
          @Override
          public boolean test(Integer i) {
          return i > 10;
          //返回值true表示留下的数据, false表示被过滤
          }
          });

    • 映射

      • Stream map(Function<? super T, ? extends R> mapper)

        • 代码

          /**

          • 映射
            */
            Stream integerStream = stream.map((item) -> {
            //return item * 2;
            return item.hashCode();
            //映射为元素的hashCode()的流
            });
    • 查看

      • Stream peek(Consumer<? super T> action)

        • 代码

          /**

          • 查看
            */
            Stream peek = stream.peek((item) -> {
            System.out.println(item);
            });
    • 其他

      • map()

        • mapToInt()
        • mapTolong()
        • mapToDouble()
      • flatMap()

        • flatMapToInt()
        • flatMapToLong()
        • flatMapToDouble()
      • unordered()

  • 有状态(statful)
    非线程安全

    必须等上一步操作拿完全部元素后才可操作

    • 限制流中个数

      • Stream limit(long maxSize)

        • 代码

          /**

          • 限制数量
            */
            Stream limit = stream.limit(10);
    • 排序

    • Stream sorted()

      • Stream sorted(Comparator<? super T> comparator)

      • 代码

        /**
        * 排序
        */
        Stream sorted = stream.sorted(new Comparator() {
        @Override
        public int compare(Integer o1, Integer o2) {
        return o1.compareTo(o2);
        }
        });

    • 其他

      • distinct()
    • skip()

终止操作

触发数据的流动, 并收集结果, 最后终止流
只要返回值不是Stream就是终止操作

  • 非短路操作
    (non-short-circuiting)

    会遍历所有元素

    • 合并

      • T reduce(T identity, BinaryOperator accumulator)

        • 代码

          /**

          • 合并
            */
            Optional reduce = stream.reduce((item1, item2) -> {

            return item1 + item2;
            });
            System.out.println(reduce.get());

    • 收集

      • collect(Collector collector)

        • 生成集合
          List collect(Collectors.toList())

          /**

          • 收集–>收集到List集合
            */
            List list1 = stream.collect(Collectors.toList());
    • 计数

      • long count()

        • 代码

          /**

          • 计数
            */
            long count = stream.count();
    • 其他

      • forEach()

        • forEachOrdered()
      • toArray()

      • max()

      • min()

  • 短路操作
    (short-circuiting)

    会在适当的时刻终止遍历, 类似break

    • anyMatch()
    • allMatch()
    • nonMatch()
    • findFirst()
    • findAny()

方法链-流式编程

  • 代码

    List list1 = list.stream.filter(i -> i > 10)
    .map(i -> i.hashCode()).sorted((i1, i2) -> i2-i1).limit(10)
    .peek(System.out::println).collect(Collectors.toList());

注意点

  • 流是一次性的, 被操作一次
    (中间操作 / 终止操作)后就被关闭了
  • 终止操作只能出现一次

List接口

实现类

  • ArrayList

    • 源码分析

      • JDK7

        • 空参构造 初始化长度为 10 的 Object[ ] 数组

        • add

          • 检验容量

          • 容量不足, 扩容

            • 1.5倍扩容

              • 仍然不足, 直接取需要的容量
            • 最大容量Integer.MAX_VALUE

              • OutOfMemoryError()
      • JDK8

        • 空参构造 Object[ ] 初始化为{ }, 并没有创建数组, 第一次调用add()时创建长度为10的数组

          • 类似单例懒汉式, 延迟数组的创建时间, 节省内存
  • LinkedList

    • 源码分析

      • JDK7

        • 两个Node 属性,first/last, 分别记录首尾节点

        • add

          • 记录新节点为last节点

          • 添加前last是否为null

            • 是–>(首次添加)

              • 记录新节点为first节点
        • remove

          • 遍历找到索引节点

            • 修改前后节点的prev, next指针
      • JDK8

        • add

          • 判断是链尾还是中间插入元素

            • 添加到链尾

              • 同上
            • 中间插入元素

              • 遍历找到索引节点

                • 添加节点
  • Vector

      • 源码分析

        • 初始化容量10
        • 2倍扩容
      • Vector有一个子类Stack(了解)

        • 栈也是通过数组实现的, 限制元素只能从数组尾部添加和删除–>先进后出, 后进先出

List接口的方法

  • void add(int index, Object ele)

    • 在index位置插入ele元素
  • boolean addAll(int index, Collection eles)

    • 从index开始将ele中的所有元素添加进来
  • Object get(int index)

    • 获取指定index位置的元素
  • int indexOf(Object obj)

    • 返回obj在集合中首次出现的索引
  • int lastIndexOf(Object obj)

    • 返回obj在集合中末次出现的索引
  • Object remove(int index)

    • 移除指定index位置的元素, 并返回原有元素
  • Object set(int index, Object ele)

    • 替换指定index位置的元素为, 并返回原有元素
  • List sublist(int fromIndex, int toIndex)

    • 返回从fromIndex到toIndex的子集合, 左闭右开

常用方法小结

    • add(Object obj)
    • remove(int index)/remove(Object obj)
    • set(int index, Object ele)
    • get(int index)
    • add(int index)
  • 长度

    • size()
  • 遍历

    • foreach()

Set接口

实现类

  • HashSet

      • 源码分析
        见HashMap

        • JDK7

          • 初始化数组长度16

            • 扩容机制

              • 负载因子, 默认0.75
          • 哈希冲突时, 将新元素存储到链表头部(数组中)

        • JDK8

          • 哈希冲突时, 将新元素添加到链表尾部
          • 链表长度达到8, 且集合容量超过64时, 将链表转换为红黑树
  • LinkedHashSet

    • (有序性)

      • 作为HashSet的子类, 遍历其内部元素时,
        可以按照添加时的顺序遍历
      • 其存储数据的结构依然与HashSet相同,
        只是在添加数据的同时, 每个节点还维护了两个引用, 分别指向其添加的前一个和后一个元素
      • 优点: 对于频繁的遍历操作, LinkedHashSet性能优于HashSet
  • TreeSet

    • 排序

      • 自然排序

        • 集合元素实现Compareable接口
        • 自然排序中, 比较两个对象是否相同的标准为: compareTo()方法返回0, 不再是equals()
      • 定制排序

        • 构造集合时传入实现Comaprator接口的比较器
        • 定制排序中, 比较两个对象是否相同的标准为: compare()方法返回0, 不再是equals()

无序性

  • 不等于随机性

    • 存储的数据并非按照数据添加顺序存储, 而是根据元素的哈希值决定的。

不可重复性

  • 先用hash算法判断(数组索引位置),
    再用hashCode, ==和equals判断元素是否相等

    • 存储元素一定要根据对象的属性
      重写hashCode()和equals()方法
      两个方法尽可能保持一致性

      • 以实现对象相等原则
        相等的对象必须具有相等的散列码
    • 如果不重写hashCode方法, 调用Object的hashCode方法, 是根据对象地址值计算的,
      地址不同, 则两个对象hashCode不同

      • (了解)编译器自动重写hashCode用到乘以系数31

        1. 选择系数的时候要选择尽量大的系数, 计算出来的hash地址越大, 所谓的冲突就越少, 查找的效率就越高

        2.hash值的大小又不宜造成数据溢出, 31只占用5bits, 相乘造成数据溢出的概率较小

        1. 31可以由 i*31==(i<<5)-i 来表示, 现在很多虚拟机里面都有做相关优化。(提高算法效率)

        2. 31是一个素数, 乘以素数可以减少hashCode冲突额概率, 还是较少哈希冲突

  • 练习

    将List内的重复数组去除

    public static List duplicateList(List list){
    HashSet set = new HashSet();
    set.addAll(list);//将List集合中所有元素添加到Set集合(去重)
    return new ArrayList(set);//通过Set集合创建List集合
    }

Map接口

实现类

  • HashMap
    主要实现类

    • 源码分析

      • 区别

        • JDK7

          • 数组+链表(哈希表)

          • 实例化

            • 实例化之后, 底层创建了默认初始化长度为16的数组: Entry<K,V>[ ] table

              • 其实Map存的数据是一个个Entry<K,V>
          • 添加元素

            • JDK7中, 新增元素添加到链表头(table中)
        • JDK8

          • 数组+链表+红黑树(哈希表)

            • 当数组某一个索引位置上的链表长度>8 && 当前数组长度>64, 该索引位置上的元素改为使用红黑树存储
          • 实例化

            • JDK8中, new HashMap()底层没有创建一个长度为16的数组

            • JDK8底层的数组是Node[], 而非Entry[]

            • JDK8中首次调用put()方法时, 创建默认长度为16的数组

            • 自定义初始化长度时, 底层创建数组长度会确保为2的幂

              这个算法在JDK8中也有优化
              JDK7中:
              int capacity = 1;
              while(capacity < intitialCapacity)
              capaciity <<= 1;

              JDK8中:
              static final int tableSizeFor(int cap) {
              int n = cap - 1;
              n |= n >>> 1;
              n |= n >>> 2;
              n |= n >>> 4;
              n |= n >>> 8;
              n |= n >>> 16;
              return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ?MAXIMUM_CAPACITY : n + 1;
              }
              原理: (对32位及以下)让为1的最高位后面位全部为1, 再+1即为2的幂。
              cap-1 : 对于2的幂, 运算后结果变为其2倍, 如: 1000–>10000, 如果-1则能解决这个问题。

              • 确保数组长度为2的幂是为了方便在映射算法时通过位运算 & 计算, 处理hash值对数组长度取模
              • x & (2^n -1) == x % 2^n
          • 添加元素

            • JDK8中, 新增元素, 添加到链表尾部
      • put(key1, value1)

        • 调用key1所在类的hashCode()方法计算哈希值, 通过hash散列算法, 映射算法计算其在Node[ ] table中的存放索引

            • 底层计算

              • hash算法

                hash散列算法 :
                static final int hash(Object key) {
                int h;
                return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
                }
                当数组的长度很短时,只有低位数的hashCode值能参与运算。而让高16位参与运算可以更好的均匀散列, 减少hash冲突。

                在这里采用^运算而不采用& , | 运算, 原因在于^能更好的保留各部分的特征, &运算的结果会向1靠拢, | 运算的结果会向0靠拢

              • 映射算法
                对数组长度取模

          • 判断桶(Bucket)是否为空

              • 添加元素到桶中
              • 比较key1和桶中已有的数据key的hash值

                • 相等

                  • 通过==和equals判断是否相同

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

code tea

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值