ArrayList
、LinkedList
和 Vector
都是用于存储和操作一组元素的数据结构,但它们在实现和性能上有一些区别。以下是它们之间的主要区别:
-
底层数据结构:
-
ArrayList
使用数组作为底层数据结构。它通过动态扩展数组的大小来实现动态大小,当数组空间不足时,会重新分配更大的数组并将数据复制到新数组中。 -
LinkedList
使用双向链表作为底层数据结构。每个元素都包含一个指向前一个元素和下一个元素的引用。 -
Vector
也使用数组作为底层数据结构,类似于ArrayList
,但Vector
支持同步,即它是线程安全的。
-
-
性能:
-
在访问元素方面,
ArrayList
在随机访问时性能较好,因为它可以直接访问数组中的元素,时间复杂度为 O(1)。但在插入和删除元素时,如果需要移动元素,性能可能较差,时间复杂度为 O(n)。 -
LinkedList
在插入和删除元素时性能较好,因为它只需要修改链表中的引用,时间复杂度为 O(1)。但在随机访问时性能较差,需要遍历链表,时间复杂度为 O(n)。 -
Vector
的性能与ArrayList
类似,但由于支持同步,可能在多线程环境中的性能开销较大。
-
-
线程安全性:
-
ArrayList
和LinkedList
默认情况下不是线程安全的,如果多个线程同时访问和修改这些数据结构,可能会导致数据不一致。 -
Vector
是线程安全的,它使用同步机制来确保多个线程可以安全地访问和修改数据。
-
-
容量调整:
-
ArrayList
(默认容量10 ,扩大1.5倍)和Vector
(默认容量10,1倍扩容) 都支持自动扩展容量,当元素数量超过当前容量时,它们会自动分配更大的内存空间来存储元素。 -
LinkedList
不需要像数组一样预先分配内存,因为它使用链表结构,可以根据需要动态分配内存。
-
-
迭代性能:
-
在迭代(遍历)元素方面,
ArrayList
通常比LinkedList
更快,因为它可以通过数组索引直接访问元素,而LinkedList
需要沿着链表遍历元素。
-
Hashtable:
线程安全,键值都不为null,动态扩容超过阈值2倍加1,初始默认容量11,负载因子.075
构造4种:
public Hashtable()
public Hashtable(int initialCapacity)
public Hashtable(int initialCapacity,float loadFactor)
public Hashtable() //传入一个集合
常用方法:
Enumeration<V> elements() //返回此哈希表中值的枚举
Enumeration<K> keys() //返回此哈希表中键的枚举
HashMap与Hashtable的区别:
-
都实现了Map接口,都存储了键值对
-
HashMap初容16,扩大2倍,Hashtable处容11,扩2倍加1
-
HashMap允许null键和null值,但值允许一个,Hashtable不允许null键和null值
-
HashMap线程不安全,Hashtable线程安全
LinkedHashMap
有序,不重复,无索引
保持插入顺序
初始容量和负载因子
可以按照访问顺序排序
TreeMap:
键的升序,键不重复,无索引
构造
无参:key要能排序,实现自然排序的能力,实现Comparable
方法
higherEntry() //大于key的最小值
floorEntry() //小于等于key的最大值
headMap() //小于key的所有集合
lowerEntry() //小于key的最大值
tailMap(key,flase) //大于key的所有集合
pollFirst() //删除第一个
descendingKeySet() //倒序键集
descendingMap() //返回新的倒集,原来的不变
treeMap.subMap(2,4) //[2,4)
subMap(2,true,4,true) //[2,4]
注:treeMap的键才能排序,HashMao不行
Hashtable存放用key的hasCode对底层长度取余
Properties:
Hashtable的子类,用于处理属性文件的类,键和值都是字符串
构造3种
LinkedHashMap
多线程中使用Map,可以使用这个
构造5种
LinkedHashSet:
继承HashSet,元素唯一,插入顺序
add() //添加元素按照key的hasCode存放
集合嵌套:把一个集合当成元素,存储到另一个集合中
Jdk8新特性(Stream流)
用来处理集合和数组
Map:
Stream<Map.Entry<String,Integer>> s = hashMap.entrySet().Stream();
数组:
String<String> st = Arrays.Stream(Strings);
Stream中间流的方法:
map() //返回null,不管,返回其他,全部替换为该映射
peek 方法:
1.不改变流的元素,它只是对流中的元素进⾏操作,然后将流传递给下⼀个操作。
2.主要⽤于调试和观察流的中间结果,以便查看流中的元素状态,⽽不对流进⾏最终操作。
-
peek() 操作是惰性的,只有在最终操作(如 forEach 、 collect 、 count 等)被调⽤时才会执⾏。
在调用中间方法时一定要连续调用,否则会抛出IllegalStateException异常,提示流已经被关闭。 末端方法不能连续调用,因为此时流已经关闭,继续调用会抛出异常。如果需要进行其他操作,则需要重 新创建流。 此外,Stream 还支持并行处理,从而能够充分利用多核处理器提高处理效率
Stream流终结⽅法:
末端方法是对流的终结操作,当对某个Stream执行末端方法后该流将被关闭,并且不可再用,调用完方法之后,其结果就不再是Stream流了, 所以不支持链式编程
Collectors.toList() 将Stream流中的元素累计到一个新的List集合中并返回 Collectors.toSet() 将Stream流中的元素累计到一个新的Set集合中并返