目录
8、ConcurrentHashMap和Hashtable的区别
9、ConcurrentHashMap为什么是线程安全的?/ConcurrentHashMap线程安全的具体实现方式/底层具体实现/有没有了解过线程安全的HashMap?
10、Hashtable也是线程安全的,为什么不推荐使用Hashtable呢?
11、HashMap底层为什么要用红黑树呢?为什么不用平衡二叉树?
18、Collection和Collections的区别是什么?
1、三大集合的区别是什么?/介绍一下集合
-
Collection
-
List:存储的元素是有序的、可重复的。
-
ArrayList
-
LinkedList
-
Vector
-
-
Set:存储的元素是无序的、不可重复的。
-
HashSet
-
LinkedHashSet
-
-
TreeSet
-
-
-
Map:使用键值对(key-value)存储,key是无序的、不可重复的,value是无序的、可重复的,每个键最多映射到一个值。
-
HashMap
-
TreeMap
-
Hashtable
-
2、ArrayList和LinkedList的区别是什么?
-
ArrayList和LinkedList都是线程不安全的
-
Arraylist底层使用的是Object数组,支持随机访问;LinkedList底层使用的是双向链表数据结构,不支持随机访问
-
使用下标访问一个元素,ArrayList的时间复杂度是O(1),而LinkedList是O(n)。
3、ArrayList和LinkedList使用场景
-
如果应用程序对数据有较多的随机访问,ArrayList对象要优于LinkedList对象。
-
如果应用程序有更多的插入或者删除操作,较少的随机访问,LinkedList对象要优于ArrayList对象。
-
不过如果在List靠近末尾的地方插入,那么ArrayList只需要移动较少的数据,而LinkedList则需要一直查找到列表尾部,反而耗费较多时间,这时ArrayList就比LinkedList要快。
4、ArrayList如何去重?
-
利用HashSet唯一性的特点对ArrayList进行去重
-
使用HashSet去重后会影响元素原有的位置,可以替换为LinkedHashSet保持元素原来的顺序
HashSet<String> objects = new HashSet<>(arr1);
//或
LinkedHashSet<Integer> hashSet = new LinkedHashSet<>(arr1);
-
使用java8新特性stream进行List去重
-
使用steam的distinct()方法返回一个由不同数据组成的流,通过对象的equals()方法进行比较。
List<Integer> listWithoutDuplicates = numbersList.stream().distinct().collect(Collectors.toList());
-
利用List的contains方法循环遍历,重新排序,只添加一次数据,避免重复
for (String str : list) {
if (!result.contains(str)) {
result.add(str);
}
}
-
双重for循环去重
for (int i = 0; i < list.size(); i++) {
for (int j = 0; j < list.size(); j++) {
if(i!=j&&list.get(i)==list.get(j)) {
list.remove(list.get(j));
}
}
}
5、HashMap的底层原理实现
HashMap在jdk7中实现原理:
-
在实例化以后,底层创建了长度是16的一维数组Entry[]table。
-
首先,调用key所在类的hashCode()计算key的哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置。
-
如果这个位置上的数据为空,此时的key-value添加成功。----情况1
-
如果这个位置上的数据不为空,意味着这个位置上以链表的形式存在一个或多个数据,比较key和已经存在的一个或多个数据的哈希值:
-
如果key的哈希值与已经存在的数据的哈希值都不相同,这时key-value添加成功。----情况2
-
如果key的哈希值和已经存在的某一个数据(key2-value2)的哈希值相同,调用key所在类的equals(key2)方法比较:
-
如果equals()返回false:此时key-value添加成功。----情况3
-
如果equals()返回true:使用value替换value2。
-
-
-
补充:关于情况2和情况3:此时key-value和原来的数据以链表的方式存储。
-
在不断的添加过程中,会涉及到扩容问题,当超出临界值(且要存放的位置非空)时,扩容。默认的扩容方式:扩容为原来容量的2倍,并将原来的数据复制过来。
HashMap在jdk8中相较于jdk7在底层实现方面的不同:
-
newHashMap():