Java集合类知识点总结

一、Java集合必备元素

集合框架:根本上是Map,Set和List的实现类集合

泛型:类型的参数化

比较器:Comparable接口和Comparator接口。Comparable接口提供了CompareTo(),Comparator接口提供了Compare()和equals()

迭代器:Iterator接口。提供了很多对集合元素进行迭代的方法,包括remove(),hasNext(),next()

二、比较器和迭代器

迭代器Iterator

iterator是为了实现对Java容器(collection)进行遍历功能的一个接口。

在iterator实现了Iterator接口后,相当于把一个Collection容器的所有对象,做成一个线性表(List),而iterator本身是一个指针,开始时位于第一个元素之前。

Iterator的三个主要方法:

1.Boolean hasNext();

判断 iterator 内是否存在下1个元素,如果存在,返回true,否则返回false。(注意,这时上面的那个指针位置不变)

2.Object next();

返回 iterator 内下1个元素,同时上面的指针向后移动一位。
故,如果不断地循环执行next()方法,就可以遍历容器内所有的元素了。

3.void remove();

删除 iterator 内指针的前1个元素,前提是至少执行过1次next();
(这个方法不建议使用,建议使用容器本身的romove 方法)

比较器Comparable和comparator

1.Comparable是一个内比较器,也就是说,可以自己跟自己进行比较。提供了一个compareTo方法用于比较,也被成为自然比较方法。**如果想使用Collections.sort方法排序某个对象容器的话,该容器必须实现Comparable接口。

2.Comparator相当于一个外比较器,也就是说,不支持自己跟自己比较。提供了compare和equals两个方法。如果一个对象没有实现Comparable接口,可以使用Comparator在主类中比较两个对象之间的值。

3.Comparator相对于Comparable来说,更个性化一些:如果实现类没有实现COmparable接口,又想对两个类进行比较,就可以使用Comparator进行自定义设置;同时,实现Comparator接口比实现Comparable接口耦合性要更弱一些,所以,从耦合性上,Comparator也比Comparable更好一些。

三、集合框架

父接口:Map接口和Collection接口。

Collection子接口:Set接口和List接口。

Set:不能包含重复的元素,无序。
List:可以包含重复的元素,有序(这里的有序指的是按照索引的升序,和值无关)。

Map接口的实现类:HashMap、TreeMap、HashTable、ConcurrentHashMap等。

Set接口的实现类:HashSet、TreeSet、LinkedHashSet等。
List接口的实现类:ArrayList、LinkedList、Stack、Vector等。

四、集合类相关特性分析

有关于集合类的讨论,主要是分析一下特性:

底层数据结构

CRUD

初始容量,扩容方式,扩容时机

是否线程安全

是否允许空,是否允许重复,是否有序

1. ArrayList&Vector&LinkedList

ArrayList

  • 底层数据结构:Object数组

  • CRUD:增删时都会首先判断索引是否合法,容量是否需要改变,然后就是正常的通过检查下标对数组的增删改查。

  • 初始容量,扩容方式,扩容时机:默认初始容量为10,随着元素的增加,容量也会不断自动增长。

  • 是否线程安全:非线程安全

  • 是否允许空,是否允许重复,是否有序:允许为空,允许重复,有序(有下标)。

  • CRUD时的线程安全:

    Fail-Fast 机制
    我们知道 java.util.ArrayList 不是线程安全的,ArrayList,那么将抛出ConcurrentModificationException,这就是所谓fail-fast策略。
    这一策略在源码中的实现是通过 modCount 域,modCount 顾名思义就是修改次数,对ArrayList 内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的 expectedModCount。
    在迭代过程中,判断 modCount 跟 expectedModCount 是否相等,如果不相等就表示已经有其他线程修改了 ArrayList。
    所以在这里和大家建议,当大家遍历那些非线程安全的数据结构时,尽量使用迭代器

Vector

Vector大部分机制和ArrayList相同。下面介绍不一样的地方:

  • 初始容量,扩容方式,扩容时机:初始容量与ArrayList相同,但在扩容方式上有更多的灵活性:Vector除了定义了基础容量外,还额外定义了一个扩容因子,如果扩容因子大于0,则每次扩容增加扩容因子的容量;如果未定义大小,也就是等于0,则每次扩容2倍。

  • 是否线程安全:vector大部分方法都是用了synchronized修饰符,所以它是线程安全的。

LinkedList

  • 底层数据结构:基于链表实现

  • CRUD:常规的链表的CRUD

  • 是否线程安全:非线程安全

  • 是否允许空,是否允许重复,是否有序:允许为空,允许重复,有序

2. HashMap&HashTable&ConcurrentHashMap

HashMap

  • 底层数据结构:HashMap实际上是一个“链表散列”的数据结构,即数组、链表、红黑树的结合体。当新建一个HashMap的时候,会初始化一个数组,而数组中的每一项会根据元素个数变为链表格式或者红黑树格式。一般来说以8个元素为界限。

  • CRUD:通过计算key的hash值找到应该存入的数组中的下标,如果改下标没有元素,就存储在这里;如果有元素,就通过该项的链表往后存储。

  • 扩容问题:当元素的数量越来越多,不同key的hash值发生碰撞的概率就越来越大,当到达table数组长度*加载因子的数量时,就会进行扩容。但是在hashmap中,扩容是一个非常耗时的过程,因为需要重新计算这些数据在新table数组中的位置并进行复制处理。

  • 初始容量,扩容方式:默认初始容量为16,自定义初始容量必须为2的幂,否则会自动调整为上界2次幂;每次会增长为2倍+1。

  • 是否线程安全:非线程安全

  • 是否允许空,是否允许重复,是否有序:允许存在一个为null的key和任意个为null的value,key不允许重复,无序。

HashTable

HashTable大部分机制和HashMap相同。下面介绍不一样的地方:

  • 基础数据结构:HashMap使用数组+链表+红黑树,而HashTable使用数组+链表

  • 二者基类不同:HashMap派生于AbstractMap,HashTable派生于Dictionary。它们都实现Map, Cloneable, Serializable这些接口。AbstractMap中提供的基础方法更多,并且实现了多个通用的方法,而在Dictionary中只有少量的接口,并且都是abstract类型。

  • 是否允许空:HashMap可以允许存在一个为null的key和任意个为null的value,但是HashTable中的key和value都不允许为null。

  • 初始容量:HashMap的initialCapacity为16,而HashTable的initialCapacity为11。HashMap中初始容量必须是2的幂,如果初始化传入的initialCapacity不是2的幂,将会自动调整为大于出入的initialCapacity最小的2的幂。

  • 是否线程安全:HashMap不是线程安全的,而HashTable是线程安全的

ConcurrentHashMap

  • 底层数据结构:采用数组+链表+红黑树

  • 是否线程安全:线程安全

  • 是否允许空:HashMap可以允许存在一个为null的key和任意个为null的value,但是ConcurrentHashMap中的key和value都不允许为null。

  • 在线程安全上与HashTable的区别:
    java8以前ConcurrentHashMap使用锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候其他段的数据也能被其他线程访问。而HashTable则是一次锁住整个hash表,从而同一时刻只能由一个线程对其进行操作。
    java8以后启用了分段锁技术,改用synchronized+CAS,但是锁的单位为node,粒度更小。

3.HashSet&TreeSet&LinkedHashSet

这三个Set类都基于HashMap实现,底层使用HashMap保存所有元素。

五、常见问题

猜你喜欢

转载自www.cnblogs.com/Water2Wine/p/12469903.html