常见集合
ArrayList
List和数组的转换
list转数组
这是深拷贝
//要转换的list集合
List<String> testList = new ArrayList<String>(){{add("aa");add("bb");add("cc");}};
//使用toArray(T[] a)方法
String[] array2 = testList.toArray(new String[testList.size()]);
不能如下:
ArrayList<String> list=new ArrayList<String>();
String strings[]=(String [])list.toArray();
因为toArray()返回的是一个Object[], 不能上转下
数组转list
可以使用asList() 或者 Collections.addAll()
不过你用asList,是浅拷贝,要受影响的。可以new一下,就不受影响了。
//下面的是浅拷贝,会受影响
List<String> arrayList=Arrays.asList(arrays);
//下面的不是浅拷贝,是深拷贝
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arrays));
//下面是深拷贝
List<String> list2 = new ArrayList<String>(arrays.length);
Collections.addAll(list2, arrays);
List的线程安全问题
ArrayList和LinkedList都不是线程安全的
vector是线程安全的数组,但是其所有方法都加上锁了,效率很低
要实现List的线程安全,可以使用 Collections.synchronizedList,先看一下它的使用方法.
List<String> list = Collections.synchronizedList(new ArrayList<String>());
list.add("1");
list.add("2");
list.add("3");
synchronized (list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext()) {
//foo(i.next());
System.out.println(i.next());
}
}
他的源码操作和vector类似,也是加锁
public E get(int index) {
synchronized (mutex) {return list.get(index);}
}
add()等方法的时候是加了synchronized关键字的,但是listIterator(),iterator()却没有加.所以在使用的时候需要加上synchronized.
HashMap
HashMap实现原理
- 底层使用hash表数据结构,即数组+(链表 | 红黑树)
- 添加数据时,计算key的值确定元素在数组中的下标
key相同则替换
不同则存入链表或红黑树中 - 获取数据通过key的hash计算数组下标获取元素
jdk1.7和jdk1.8的区别
JDK1.8之前采用的拉链法,数组+链表
JDK1.8之后采用数组+链表+红黑树,链表长度大于8且数组长度大于64则会从链表转化为红黑树
HashMap的put方法的具体流程
讲一讲HashMap的扩容机制
hashMap的寻址算法
- 计算对象的 hashCode()
- 再进行调用 hash() 方法进行二次哈希, hashcode值右移16位再异或运算,让哈希分布更为均匀
- 最后 (capacity – 1) & hash 得到索引
为何HashMap的数组长度一定是2的次幂?
- 计算索引时效率更高:如果是 2 的 n 次幂可以使用位与运算代替取模
- 扩容时重新计算索引效率更高: hash & oldCap == 0 的元素留在原来位置 ,否则新位置 = 旧位置 + oldCap
hashmap在1.7情况下的多线程死循环问题
在jdk1.7的hashmap中在数组进行扩容的时候,因为链表是头插法,在进行数据迁移的过程中,有可能导致死循环。
JDK 8 将扩容算法做了调整,不再将元素加入链表头(而是保持与扩容前一样的顺序),尾插法,就避免了jdk7中死循环的问题。
HashSet与HashMap的区别
(1)HashSet实现了Set接口, 仅存储对象; HashMap实现了 Map接口, 存储的是键值对.
(2)HashSet底层其实是用HashMap实现存储的, HashSet封装了一系列HashMap的方法. 依靠HashMap来存储元素值,(利用hashMap的key键进行存储), 而value值默认为Object对象. 所以HashSet也不允许出现重复值, 判断标准和HashMap判断标准相同, 两个元素的hashCode相等并且通过equals()方法返回true.
HashTable与HashMap的区别
主要区别:
区别 | HashTable | HashMap |
---|---|---|
数据结构 | 数组+链表 | 数组+链表+红黑树 |
是否可以为null | Key和value都不能为null | 可以为null |
hash算法 | key的hashCode() | 二次hash |
扩容方式 | 当前容量翻倍 +1 | 当前容量翻倍 |
线程安全 | 同步(synchronized)的,线程安全 | 非线程安全 |
在实际开中不建议使用HashTable,在多线程环境下可以使用ConcurrentHashMap类