集合
原文出自:https://zhuanlan.zhihu.com/p/267545042

线程安全:
Vector、HashTable
线程不安全:
HashMap、TreeMap、HashSet、ArrayList、LinkedList
2、 Arraylist与 LinkedList 区别
-
Arraylist 底层是数组;LinkedList 底层是双向循环链表数据结构;(后面的区别也是因为底层数据结构不同引发的)
-
ArrayList查询快,增删慢;LinkedList查询慢,增删快。
-
ArrayList的空间浪费主要体现在list列表的结尾会预留一定的容量空间,而LinkedList的空间花费则体现在存放直接后继和直接前驱以及数据)。
3、 HashMap 和 Hashtable 的区别:
-
同步性:Hashtable 的方法是 Synchronize 的,线程安全;而 HashMap 是线程不安全的,不是同步的。所以只有一个线程的时候使用hashMap效率要高。(线程安全性也附带着效率的问题)
-
值:HashMap对象的key、value值均可为null。HahTable对象的key、value值均不可为null。
-
容量:HashMap的初始容量为16,Hashtable初始容量为11,两者的填充因子默认都是0.75。(当容量使用75%时就进行扩容)
-
HashMap扩容时是当前容量翻倍即:capacity * 2,Hashtable扩容时是容量翻倍+1 即:capacity * 2+1。
HashMap可以通过下面的语句进行同步:(collections:集合的工具类)
Map m = Collections.synchronizeMap(hashMap);
4、 HashSet 和 HashMap 区别
HashSet 底层就是基于 HashMap 实现的。只不过HashSet里面的HashMap所有的value都是同一个Object而已(key值就成为了存储数据,不再是指向标),因此HashSet也是非线程安全的。

5、ConcurrentHashMap和Hashtable的区别(没看明白)
JDK1.7的 ConcurrentHashMap 底层采用 分段的数组+链表 实现,JDK1.8 采用的数据结构跟 HashMap1.8的结构一样,数组+链表/红黑二叉树。Hashtable 和 JDK1.8 之前的 HashMap 的底层数据结构类 似都是采用 数组+链表 的形式,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的;
① 在JDK1.7的时候,ConcurrentHashMap(分段锁) 对整个桶数组进行了分割分段(Segment),每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。 到了 JDK1.8 的时候已经摒弃了Segment的概念,而是直接用 Node 数组+链表+红黑树的数据结构来实现,并发控制使用 synchronized 和 CAS 来操作。(JDK1.6以后 对 synchronized锁做了很多优化) 整个看起来就像是优化过且线程安全的 HashMap,虽然在JDK1.8中还能看到 Segment 的数据结构,但是已经简化了属性,只是为了兼容旧版本;
② Hashtable(同一把锁) :使用 synchronized 来保证线程安全,效率非常低下。当一个线程访问同步方法时,其他线程也访问同步方法,可能会进入阻塞或轮询状态,如使用put 添加元素,另一个线程不能使用 put 添加元素,也不能使用 get,竞争会越来越激烈效率越低。
6、Set和List的区别
-
Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。都可以存储null值,但是set不能重复所以最多只能有一个空元素。
-
Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>。
-
List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 <实现类有ArrayList,LinkedList,Vector> 。
7、 ArrayList 与 Vector 的区别:
共同点: 都实现了List接口,都是有序的集合,我们可以按位置的索引号取出元素,其中数据都是可以重复的,这是与hashSet最不同的,hashSet不可以按照索引号去检索其中的元素,也不允许有重复的元素。
区别:
-
同步性:Vector是线程安全的,即线程同步,ArrayList是不安全的,如果有多个线程访问到集合,最好使用Vector,因为不需要我们自己再去考虑和编写线程安全的代码;如果只有一个线程会访问到集合,那最好是使用ArrayList,因为它不考虑线程安全,效率会高些。
-
数据增长:ArrayList 与 Vector 都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就需要增加 ArrayList 与 Vector 的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间要取得一定的平衡。Vector 默认增长为原来两倍,而 ArrayList 的增长策略在文档中没有明确规定(从源代码看到的是增长为原来的 1.5 倍)。ArrayList 与 Vector 都可以设置初始的空间大小,Vector 还可以设置增长的空间大小,而 ArrayList 没有提供设置增长空间的方法。
8、HaspMap与TreeMap的区别:
-
HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。
-
在Map 中插入、删除和定位元素,HashMap是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode()和 equals()的实现。
9、Collection和Collections的区别
Collection是单列集合的顶层接口,Map是双列集合的顶层接口
Collections是一个集合的工具类,提供了排序、查找等操作集合的一些常用方法。
10、 Collection框架中实现比较要怎么做?
第一种,实体类实现Comparable<T>接口,并实现 compareTo(T t) 方法,我们称为内部比较器。
第二种,创建一个外部比较器,这个外部比较器要实现Comparator接口的 compare(T t1, T t2)方法。
comparable 和 comparator的区别?
-
comparable接口实际上是出自java.lang包,它有一个 compareTo(Object obj)方法用来排序
-
comparator接口实际上是出自 java.util 包,它有一个compare(Object obj1, Object obj2)方法用来排序
一般我们需要对一个集合使用自定义排序时,我们就要重写compareTo方法或compare方法,当我们需要对某一个集合实现两种排序方式,比如一个song对象中的歌名和歌手名分别采用一种排序方法的话,我们可以重写compareTo方法和使用自制的Comparator方法或者以两个Comparator来实现歌名排序和歌星名排序,第二种代表我们只能使用两个参数版的Collections.sort().
例子:
public class ComparatorTest {
public static void main(String[] args) {
Student xiaoming = new Student("xiaoming", 20);
Student xiaohong = new Student("xiaohong", 21);
Student xiaogang = new Student("xiaogang", 19);
List<Student> list = new ArrayList<Student>();
list.add(xiaohong);
list.add(xiaoming);
list.add(xiaogang);
//因为Student类已经重写了compareTo方法
System.out.println("已重写后的list --->>>" + list);
//自定义排序
Collections.sort(list, new Comparator<Student>() {
