Java容器
容器
java容器,或者应该叫java集合框架更为贴切。Java集合框架提供了一套性能优良、使用方便的接口和类,它们
位于java.util包中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rDt1Xuq3-1609855908938)(D:\notes\JavaSE\容器.png)]
Collection 接口
集合作为容器应该具有的功能(增,删,改,查),
不一定全有。
集合的基本操作:增加,删除,判断,取出
序号 | 方法名 | 作用 |
---|---|---|
1 | add(Object obj) | 添加,存储的是对象的引用 |
2 | size() | 容器中元素的实际个数 |
3 | remove(Object obj) clear() removeAll(Collection<?>c) retainAll(Collection<?>c) | 删除 |
4 | contains(Object obj) isEmpty() | 判断元素 |
5 | iterator() | 遍历元素 |
List接口
特点:有序,不唯一(可重复)
List特有方法
序号 | 方法名 | 作用 |
---|---|---|
1(增) | add(index,element) addAll(index,Collection) addAll(Collection) | 在指定索引的位置上插入元素 在指定的引的位置上插入整个集合的元素 在结束插入整个集合的元素 |
2(删) | remove(index) | 根据索引删除指定的元素 |
3(改) | set(index,element) | 使用element替换指定索引位置上的元素 |
4(查) | get(index) subList(from,to) listIterator(); | 获取元素 |
ArrayList
-
底层数据结构是数组。线程不安全
-
默认初始化容量为10,如果指定,那么初始化成对应容量。
-
ArrayList是基于动态数组实现的,在增删时候,需要数组的拷贝复制。(navite 方法由C/C++实现)
-
add方法:(1)检查是否需要扩容 ,(2)添加元素
-
扩容,扩容到原来的1.5倍
-
删除元素时不会减少容量,若希望减少容量则调用trimToSize()
-
它不是线程安全的。它能存放null值。
LinkedList
- 底层数据结构是双向链表。线程不安全
- LinkedList实现了Deque接口,因此,我们可以操作LinkedList像操作队列和栈一样
Vector
Vector是jdk1.2的类了,比较老旧的一个集合类。
- 底层数据结构是数组。线程安全(Vector是同步的),但是有性能损失
- ArrayList在底层数组不够用时在原来的基础上扩展0.5倍,Vector是扩展1倍。
如果想要ArrayList实现同步,可以使用Collections的方法:**
List list = Collections.synchronizedList(new ArrayList(…));
ArrayList增删慢不是绝对的(在数量大的情况下):
- 如果增加元素一直是使用add()(增加到末尾)的话,那是ArrayList要快
- 一直删除末尾的元素也是ArrayList要快【不用复制移动位置】
- 至于如果删除的是中间的位置的话,还是ArrayList要快!
但一般来说:增删多还是用LinkedList
CopyOnWriteArrayList
CopyOnWriteArrayList是同步List的替代品
- 在修改时,复制出一个新数组,修改的操作在新数组中完成,最后将新数组交由array变量指向。
- 写加锁,读不加锁
- 遍历Vector/SynchronizedList是需要自己手动加锁的。CopyOnWriteArrayList使用迭代器遍历时不需要显示加锁
Set接口
特点:元素不可重复
可以先了解Map,了解了Map就自然能弄懂Set。
HashSet
无序,允许为null,底层是HashMap(散列表+红黑树),非线程同步
TreeSet
有序,不允许为null,底层是TreeMap(红黑树),非线程同步
保证元素的排序方式
LinkedHashSet
迭代有序,允许为null,底层是HashMap+双向链表,非线程同步
Map接口
HashMap
-
JDK8中HashMap的底层是:数组+链表(散列表)+红黑树
-
无序,允许为null,非同步
-
初始容量(16)和装载因子(0.75)对HashMap影响挺大的,设置小了不好,设置大了也不好
装载因子初始值大了,可以减少散列表再散列(扩容的次数),但同时会导致散列冲突的可能性变大(散列冲突也是耗性能的一个操作,要得操作链表(红黑树)
-
扩容:原始容量 * 2,底层数组的容量一定为2的整数次幂
HashMap并不是直接拿key的哈希值来用的,它会将key的哈希值的高16位进行异或操作,使得我们将元素放入哈希表的时候增加了一定的随机性。
还要值得注意的是:并不是桶上有8位元素的时候它就能变成红黑树,它得同时满足我们的散列表容量大于64才行的~
HashTable
- 底层是: 数组 + 链表
- 线程安全的,但性能比较低
- 不允许key和value为null
- 默认初始化容量11
- 扩容 原始容量 * 2 + 1
Hashtable是个过时的集合类,不建议在新代码中使用,不需要线程安全的场合可以用HashMap替换,需要线程安全的场合可以用ConcurrentHashMap替换
TreeMap
- 实现了NavigableMap接口,而NavigableMap接口继承着SortedMap接口,所以TreeMap是有序的!
- 底层是红黑树,它方法的时间复杂度都不会太高:log(n)
- 非同步的,想要同步可以使用Collections来进行封装
LinkedHashMap
-
底层是散列表和双向链表
-
允许为null,不同步
-
插入的顺序是有序的(底层链表致使有序)
-
装载因子和初始容量对LinkedHashMap影响是很大的~
-
初始容量对遍历没有影响——因为它遍历的是LinkedHashMap内部维护的一个双向链表,而不是散列表(当然了,链表双向链表的元素都来源于散列表)
-
LinkedHashMap可以设置两种遍历顺序:
访问顺序(access-ordered)
插入顺序(insertion-ordered)
默认是插入顺序的
ConcurrentHashMap
-
JDK1.8底层是散列表+红黑树
-
ConCurrentHashMap支持高并发的访问和更新,它是线程安全的
-
检索操作不用加锁,get方法是非阻塞的
-
key和value都不允许为null
-
Hashtable是将所有的方法进行同步,效率低下。而ConcurrentHashMap作为一个高并发的容器,它是通过部分锁定+CAS算法来进行实现线程安全的。CAS算法也可以认为是乐观锁的一种~
-
在高并发环境下,统计数据(计算size…等等)其实是无意义的,因为在下一时刻size值就变化了。
-
get方法是非阻塞,无锁的。重写Node类,通过volatile修饰next来实现每次获取都是最新设置的值
Iterator接口
所有实现了Collection接口的容器类都有一个iterator方法用以返回一个实现了Iterator接口的对象。
▪ Iterator对象称作迭代器,用以方便的实现对容器内元素的遍历操作。
▪ Iterator接口定义了如下方法:
hasNext() //判断是否有元素没有被遍历
next() //返回游标当前位置的元素并将游标移动到下一个位置
remove() //删除游标左面的元素,在执行完next之后该
操作只能执行一次
Collection返回的是Iterator迭代器接口,而List中又有它自己对应的实现–>ListIterator接口
ListIterator可以往前遍历,添加元素,设置元素
Comparable接口
所有可以“排序”的类都实现了java.lang.Comparable 接口,Comparable接口中只有一个方法
public int compareTo(Object obj);
//返回 0 表示 this == obj
//返回正数 表示 this > obj
//返回负数 表示 this < obj
Collections.sort(list,new MyComparator());
实现了Comparable 接口的类通过实现 comparaTo 方法从而确定该类对象的排序方式。
Collections 工具类
Collections和Collection不同,前者是集合的操作类,后者是集合接口
Collections提供的静态方法
addAll():批量添加
sort():排序
binarySearch():二分查找
fill():替换
shuffle():随机排序
reverse():逆序