集合
Collection
下图中实线表示继承,虚线表示实现:
常用方法:
add
:添加元素;remove
:删除元素;contains
:查找元素是否存在;size
:获取元素个数;isEmpty
:判断是否为空;clear
:清空;addAll
:添加多个元素;containsAll
:多个元素是否都存在;removeAll
:删除多个元素。
因为存储的是对象(Object
),如果添加元素为基本数据类型会自动装箱
。
迭代器
迭代器(iterator
)用于遍历 Collection
中的元素。所有实现了 Collection
接口的集合类都有一个 iterator()
方法,用以返回一个迭代器对象。
主要方法:
hasNext
:没有指针下移操作,只是判断是否存在下一个元素;next
:指针下移并返回指针所指向的元素;remove
:删除指针指向的元素。
1 | Iterator<Integer> iterator = coll.iterator(); |
在调用 next
方法之前必须先调用 hasNext
进行检测。否则如果下一条记录无效,直接调用 next
将抛出 NoSuchElementException
异常。
增强 for
循环,底层使用迭代器实现,写法简便,可以代替 iterator
进行遍历。用于遍历集合或数组。
1 | for (Integer ele : coll) { |
List
List 中元素有序且可重复,支持索引,可根据索引获取元素。
除继承而来的方法外,List 还新增了一些根据索引操作集合元素的方法,常用方法:
void add(int index, Object ele)
:在index
位置插入ele
元素;boolean addAll(int index, Collection eles)
:从index
位置开始将eles
中的所有元素添加进去;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
位置的元素为ele
;List subList(int fromlndex, int tolndex)
:返回从fromlndex
到tolndex
位置的子集合。
ArrayList
- 使用数组作为数据结构,底层维护了一个
Object[]
类型的数组elementData
; - 当创建
ArrayList
对象时,如果使用无参构造器,则初始elementData
容量为0
,第1
次添加时,则扩容elementData
为10
,如需再次扩容,则扩容为1.5
倍;若使用有参构造器,初始大小为参数指定大小,之后直接按1.5
倍进行扩容; ArrayList
在当前容量不足以容纳新元素时才进行扩容操作,扩容时会创建一个新的数组,并将原有数组中的元素复制到新数组中;- 非线程安全。
Vector
使用数组作为数据结构,底层同样维护了一个
Object[]
类型的数组elementData
;扩容机制与
ArrayList
基本一致,当使用无参构造器创建时,默认初始大小为10
。如果元素数量超过了当前容量,则创建一个为当前容量2
倍的新数组,然后将原有元素复制到新的数组中;线程安全,通过使用
synchronized
修饰方法来实现。但是由于锁住了整个Vector
对象,效率不高;
LinkedList
使用双向链表作为数据结构,它存储了指向头节点和尾节点的引用;
不需要扩容机制,添加元素时修改节点之间的引用关系即可;
非线程安全。
Set
Set 中元素无序且不能包含重复元素,不支持索引。
除了继承自
Collection
接口的方法外,Set
接口没有额外的新增方法。
HashSet
非线程安全。
HashSet
的底层数据结构是哈希表
,它实际上通过 HashMap
来实现。HashSet
内部维护了一个 HashMap
实例,HashSet
中的元素被存储在 HashMap
的键
中,而 HashMap
中的值则都被设置为同一个类常量,仅仅作为占位存在。
当向 HashSet
添加元素时,会先得到这个元素的 hashCode
,再根据 hash规则
将元素存储在指定的数组位置。如果造成 hash冲突
,会调用元素的 equals
方法与冲突元素(链表或树中的元素)进行比较,如果某次比较返回 true
,则放弃添加,否则将元素添加到链表或红黑树中。
规范:如果两个对象通过 equals
方法比较是相等的,则它们的 hashCode
也应该是相等的。
扩容机制
:第一次添加元素时,table
数组扩容到 16
,临界值为 16*0.75=12
。如果数组单元占用个数超过临界值,会创建一个新数组,其容量为原来的两倍 16*2=32
,新临界值为 32*0.75=24
,以此类推。如果总元素个数 >=64
并且存在长度达到 8
的链表,则进行树化,将长度达到阈值的链表转换成红黑树。
1 | HashSet<Object> hashSet = new HashSet<>(); |
1 | [com.scarf.User@29453f44, scarf, com.scarf.User@5cad8086] |
1 | // 原因是 String 重写了 hashcode 以及 equals 方法 |
1 | user1哈希码: 1588970020 |
LinkedHashSet
LinkedHashSet
底层通过 LinkedHashMap
实现,通过在 HashSet
的基础上新增双向链表用于维护元素的顺序。能够保留元素插入的顺序,因此它是有序的集合。LinkedHashSet
的扩容机制与 HashSet
一致,同时也是非线程安全的。
数组单元是可以存储元素的,为了方便起见将数组中的元素提到外面。
TreeSet
- 使用
红黑树
作为数据结构,底层使用TreeMap
来实现,元素存储在key
中,value
同样使用类常量占位; - 非线程安全;
- 特点是能够按照指定的比较器(
Comparator
)进行排序,并且支持快速的集合操作,比如范围查询、查找最小/最大元素等。
1 | TreeSet<String> treeSet = new TreeSet<>(String::compareTo); // 按字母表顺序排序 |
1 | // 按长度进行排序 |
Map
下图中实线表示继承,虚线表示实现:
Map 中 key
不能重复,如果添加相同的 key
,会覆盖原来的值。
常用方法:
put
:添加元素;remove
:根据键删除元素;get
:根据键获取值;size
:获取元素个数;isEmpty
:判断元素个数是否为空;clear
:清除元素;containsKey
:查找键是否存在;keySet
:获取所有的键;entrySet
:获取所有键值对;values
:获取所有值。
HashMap
- 底层数据结构采用
数组+链表+红黑树
,使用key
进行hash
和equals
判断,与value
无关; - 扩容机制在
HashSet
中已阐述; - 非线程安全。
对于 LinkedHashMap
,它同样在 HashMap
的基础上新增了双向链表来使元素有序。
HashTable
- 键和值都不能为
null
,否则将抛出NullPointerException
空指针异常; - 使用
数组+链表
的方式来处理哈希冲突,链表并不会被转成红黑树; - 默认数组初始大小为
11
,装载因子还是0.75
,扩容时会创建一个新数组,其容量为原来的2 倍 + 1
; - 线程安全,通过使用
synchronized
修饰方法来实现。
Properties
主要用于操作配置文件。
- 继承自
HashTable
,使用键值对的形式保存数据,键和值同样都不能为null
; - 数据结构以及扩容机制和
HashTable
一致; - 使用了
synchronized
修饰了setProperty()
和load()
等方法。如果只是调用这些同步的方法,那么在多线程环境下是安全的。
TreeMap
相关已在 TreeSet
中阐述。
1 | // 按字母表排序 key |
1 | // 按 key 长度排序 |
Collections
Collections
是一个可以操作Set
、List
和Map
的工具类。
常用方法:
reverse(List)
:反转 List 中元素的顺序;shuffle(List)
:对 List 元素进行随机排序;sort(List)
:根据元素的自然顺序对 List 进行排序;sort(List, Comparator)
:根据指定的 Comparator 排序规则对 List 进行排序;swap(List, int, int)
:交换 List 集合中两个指定位置的元素;max(Collection)
:根据元素的自然顺序,返回集合中的最大元素;max(Collection, Comparator)
:根据 Comparator 指定的顺序,返回集合中的最大元素;min(Collection)
、min(Collection, Comparator)
;frequency(Collection, Object)
:返回集合中指定元素的出现次数;copy(List dest, List src)
:将 src 中的内容复制到 dest 中;replaceAll(List list, Object oldVal, Object newVal)
:使用 newVal 替换 List 中的所有 oldVal。