Java八股文-常见集合学习记录1


常见集合

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类


文章作者: 爱敲代码の鱼儿
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 爱敲代码の鱼儿 !
  目录