Java集合-复习

划重点(面试常问的HashMap原理):

HashMap是一个“链表散列”的数据结构,即数组和链表的结合体;
HashMap的底层是一个数组结构,数组中每一项是一个链表;
HashMap初始化的时候,会初始化一个数组,Map的内部类Entry就是数组中的元素,每个Entry就是一个Key-value对,并且持有一个指向下一个元素(Entry)的引用,这就构成了链表;


常用的集合类实现类:HashSet、TreeSet、ArrayList、ArrayDeque、LinkedList、HashMap、TreeMap;


下面是集合接口的介绍:


Collection接口:

  • 是List、Set、Queue接口的父接口;
  • 集合类就像容器,容器的功能大部分都是 添加对象、删除对象、清空容器、判断容器是否为空 等;
  • 继承了Iterable接口,Java8为Iterable接口新增了一个foreach方法,所以Collection类型的对象可以使用foreach来遍历,foreach可以使用lambda表达式;
  • 此接口的removeIf(Predicate<? super E> filter)方法,用来过滤集合,过滤后的集合会被改变;
  • 此接口的stream方法用于操作集合,stream是流式API,详细使用方法可参考API文档;

Iterator接口:

  • 中文意思“迭代器”,此接口主要用来遍历(迭代范文)Collection集合;
  • 有hasNext()、next()、remove()、和Java8新增的forEachRemaining(Consumer<? super E> action)方法,Consumer是函数式接口,可以使用lambda表达式;

Set集合:

  • 集合内的元素 无序不可重复;

    HashSet:

    • 按Hash算法来存储集合中的元素,因此具有很好的存取和查找性能;
    • 集合元素值可以为null;
    • 判断集合内两个元素是否相等方式为:两个元素的equals为true并且hashCode值相等;

    LinkedHashSet(HashSet的子类):

    • 有序的;
    • 使用Hash算法来存储集合中的元素,使用双向链表来维护内部顺序,因此在迭代速度上有很大优势,但是需要维护元素的插入顺序,所以性能略低于HashSet;

    TreeSet(TreeSet实现SortedSet接口,SortedSet继承Set接口):

    • 有序,排序状态;
    • 使用红黑树的数据结构来存储集合元素;
    • 集合内的元素必须是同一类型,就是说只能添加同一种类型的对象;
    • 有两种排序方法:
      • 自然排序:使用集合元素的obj1.compareTo(obj2)方法进行对比,按升序排列,compareTo是Comparable接 口的方法,所以元素必须实现该接口;
      • 定制排序:通过Comparator接口实现定制排序,创建TreeSet对象时传入一个Comparator对象,接口里面包含一个compare(T o1,T o2)方法,此接口是函数式接口,可以使用lambda表达式;

    EnumSet:

    • 专门为枚举类设计的集合类;
    • 集合内所有元素必须都是指定枚举类型的枚举值;
    • 有序;
    • 集合元素值不能为null;
    • 没有暴露构造器,使用allOf方法来创建对象;
  • HashSet、LinkedHashSet、TreeSet、EnumSet四个类一般都是使用HashSet,HashSet性能总是比TreeSet好(特别是常用的添加、查询的操作),只有需要一个保持排序Set时,才用TreeSet;
  • LinkedHashSet在插入、删除操作时比HashSet略微慢了点,这是由于维护链表造成的,但是链表遍历更快;
  • EnumSet是性能最好的,但是它只能保存同一个枚举类型的枚举值作为元素;
  • 这四个类都是线程不安全的;

List集合:

  • 有序,可重复;
  • List是线性表接口;
  • List的sort(Comparator<? super E> c)方法,传入一个Comparator对象,接口里面包含一个compare(T o1,T o2)方法,此接口是函数式接口,可以使用lambda表达式;
  • List的replaceAll(UnaryOperator operator)方法,传入一个UnaryOperator对象,接口里面包含一个R apply(T t)方法,此方法传入一个参数,返回对改参数操作后的结果,此接口是函数式接口,可以使用lambda表达式;
  • List额外提供了一个listIterator()方法,返回一个ListIterator对象,ListIterator接口继承了Iterator接口,在Iterator的基础上增加了向前迭代的功能,并且能增加元素;

    ArrayList和Vector实现类:

    • ArrayList和Vector是List接口的两个典型的实现类,通常都使用ArrayList,默认长度为10;
    • ArrayList和Vector是基于数组实现的;
    • 元素可以为null;
    • ArrayList是线程不安全的,Vector是线程安全的,但是一般不用Vector;
    • Vector提供了一个stack子类,用于模拟“栈”的数据结构,是一个古老的集合,性能较差,不推荐使用;
    • ArrayList在每次add的时候会检查数组长度是否超出容量,超过就创建一个目前数组1.5倍的数组(Vector是2倍),将目前数组数据复制过去;

    LinkedList实现类:

    • LinkedList实现了List接口和Deque接口,可以根据索引随机访问集合中的元素,也可以当成双端队列来使用(既可以模拟“栈”也可以当成队列使用);
    • 内部以链表的形式来保存集合中的元素,因此随机访问数据性能较差,但在插入、删除元素时性能较好(只需要改变指针所指的地址即可);

Queue集合:

  • 模拟“队列”数据结构,数据先进先出;

    PriorityQueue实现类:

    • 元素不能为null;
    • 队列中的元素会按大小重新排序,因此元素并不是先进先出,而是最小的元素先出(违反了队列的基本规则:先进先出);
    • 只能添加同一种类型的对象;
    • 有两种排序方法和TreeSet一样;

    Deque接口与ArrayDeque实现类:

    • Deque接口是Queue接口的子接口,是一个双端队列,允许从两端来操作队列的元素;
    • Deque接口提供了一个典型的实现类ArrayDeque,是一个基于数组实现的双端队列,默认长度为16;
    • ArrayDeque和ArrayList的底层实现机制基本相似,都是采用一个动态的、可重分配的Object[]数组;
    • ArrayDeque可以当做队列使用,也可以当做“栈”使用;
  • 数组以一块连续内存区来保存所有的数组元素,数组的随机访问性能最好,所以以数组作为底层实现的集合在随机访问时性能较好,以链表为底层实现的集合在插入、删除操作时性能较好,总体来说ArrayList的性能比LinkedList的性能要好;
  • 遍历以数组为底层实现的集合元素时,最好用get()方法来操作,遍历以链表为底层实现的集合时,则使用Iterator来操作;

Map集合:

  • 用于保存具有映射关系的数据(key-value键值对);
  • key不能重复;
  • Map和Set的关系非常密切,Map提供了一个Entry内部类来封装Key-value对,而计算Entry存储时只考虑key,从源码看, Java是先实现了Map,然后通过包装一个所有value为null的Map就实现Set;

    HashMap和Hashtable实现类:

    • 无序的;
    • HashMap是线程不安全的,HashTable是线程安全的,前者性能更高,后者比较古老,HashMap允许null作为key或value,Hashtable不允许,尽量少用Hashtable;
    • HashMap和Hashtable判断key相等时需要equals返回true并且hashCode值相等,判断value相等只需要equals返回true即可;

    LinkedHashMap实现类(HashMap的子类):

    • 有序的;
    • 使用双向链表来维护key-value的次序,迭代顺序与插入顺序保持一致;
    • 使用链表来维护内部顺序,因此在迭代速度上有很大优势,但是需要维护元素的插入顺序,所以性能略低于HashMap;

    Properties类(Hashtable的子类):

    • 改对象在处理属性文件是特别方便(Windows的ini文件就是一种属性文件),属性文件和Map相映射,Properties的key和value都是String类型的;
    • Properties也可以保存和读取XML文件;

    SortedMap接口和TreeMap实现类(TreeMap实现SortedMap接口,SortedMap继承Map接口):

    • 有序,排序状态;
    • 线程不安全;
    • 使用红黑树的数据结构来存储集合元素;
    • 集合内的元素必须是同一类型,就是说只能添加同一种类型的对象;
    • 有两种排序方法:
      • 自然排序:使用集合元素的obj1.compareTo(obj2)方法进行对比,按升序排列,compareTo是Comparable接 口的方法,所以元素必须实现该接口;
      • 定制排序:通过Comparator接口实现定制排序,创建TreeSet对象时传入一个Comparator对象,接口里面包含一个compare(T o1,T o2)方法,此接口是函数式接口,可以使用lambda表达式;
    • 几乎和TreeSet一样,实际上Set就是一个所有value都为null的Map集合;

    WeakHashMap实现类:

    • 和HashMap基本相似,区别在于HashMap的key保留了对实际对象的强引用,而WeakHashMap只保留了对实际对象的弱引用,这以为着如果WeakHashMap的key所引用的对象没有被其他强引用变量所引用的话,则这些key所引用的对象可能被垃圾回收;

    IdentityHashMap实现类:

    • 和HashMap基本相似,区别在于HashMap判断两个key值是否相等是用equals和hashCode来判断,IdentityHashMap则是使用严格相等“==”来判断;

    EnumMap实现类:

    • 线程不安全;
    • 有序;
    • 集合元素值不能为null;
    • 创建EnumMap时必须指定一个枚举类;
  • HashMap和Hashtable实现机制几乎一样,底层是用数组实现的,但是Hashtable是一个古老的、线程安全的集合,所以HashMap通常比Hashtable要快;
  • TreeMap通常别HashMap和Hashtable要慢(尤其在插入、删除时更慢),因为TreeMap底层使用红黑树来管理Key-value对,TreeMap的好处是里面的Key-value对一直处于有序状态,无需进行排序操作,当TreeMap被填充后可以使用Arrays.binarySearch(new TreeMap().keySet().toArray(), index)快速查询对象;
  • LinkedHashMap比HashMap慢一点,因为它需要维护链表来保持Key-value的添加顺序;
  • EnumMap是性能最好的,但是它只能使用同一个枚举类型的枚举值作为key;
  • 一般都是使用HashMap,HashMap就是为了快速查询而设计的(底层使用数组来实现);
  • HashMap、HashSet及其子类和Hashtable都是采用hash算法来决定集合中元素的存储位置,并通过hash算法来控制集合的大小,hash表里可以存储元素的位置被称为“桶(bucket)”,hash算法可以根据hashCode值计算出“桶”的存储位置,hash表的状态是open的,在发生“hash冲突”的情况下,单个桶会存储多个元素,这些元素以链表形式存储,必须按顺序搜索,hash表里有一个负载极限(0~1),当hash表的负载因子到达负载极限时(默认0.75),hash表会成倍的增加容量(桶的数量),并将所有的对象重新分配,放入新的桶中,这称之为rehashing;
  • 前面提到的Vector及其子类和Hashtable这些古老的集合类有一个遍历迭代器接口为Enumeration,是Iterator的古老版本;

Java提供了一个操作Set、List和Map等集合的工具类:Collections
  • Collections提供了常用的类方法如:集合内元素的反转、随机、排序、交换、查找、替换等;
  • Collections还提供了多个synchronizedXxx()方法,可以将指定集合类包装成线程同步的集合;
  • Collections还提供了三个类方法来返回一个不可变的集合(只读):emptyXxx()、singletonXxx()、unmodifiableXxx();

未完待续~

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值