面试整理-集合框架

Collection

List

        最大的特点是有序,可重复。

ArrayList:

        底层用数组实现,默认的大小为10,每次扩容为原来容量的1.5倍;

        int newCapacity = oldCapacity + (oldCapacity >> 1);

        查找的过程为O(1),但是增加和删除元素均摊复杂度都是O(n),且要移动元素,如果在尾部操作,则效果较好;

LinkList:

        底层链表实现,查找和增删的复杂度都是O(n),只有增删的操作较多,且都不在尾部才考虑使用;

Vector:

        线程安全,底层数组实现,使用了太多的Synchronized,因此目前已被弃用;和ArrayList一样需要扩容,但扩容的大小是默认是原有的2倍

Queue & Deque

        Queue 是一端进另一端出的线性数据结构;而 Deque 是两端都可以进出的;

Set

HashSet:采用HashMap的key来存储元素,无序,基本操作都是O(1)的复杂度。

LinkedHashSet:是一个HashSet+LinkedList的结构,既拥有O(1)的复杂度,又能够保留插入的顺序。

TreeSet:采用红黑树结构,可以用自然排序或者自定义比较器排序,查询速度没有HashSet快

        每个set的底层实现都是对应的map,value上放persent,是一个静态的object,每个key都指向这个object;

HashMap:

        由数组和链表构成的数据结构,每个数组都存放了key-value这样的实例,在Java7叫entry,在Java8叫node,本身所有的位置都是null,在put是会根据key的hash去计算一个index的值,即插入的位置。由于数组的长度是有限的,而且hash本身存在概率性,所以可能有两个对象hash到一个值上,就形成了链表;

头插与尾插:

        Java8之前是头插法,新来的值会取代原有的值,原有的值推到链表中去;好处是解决循环链表的问题,头插法在resize扩容时,如果是多线程操作,可能会导致循环链表的形成。即便解决了循环链表的问题,在多线程环境下还是不建议使用HashMap,因为无法保证上一秒put的值下一秒get还是原值,总归是线程不安全的。

HashMap扩容:

        由于数组容量是有限的,达到一定数量就会扩容(resize),由两个因素决定,capacity::当前长度,默认16;LoadFactor:负载因子,默认值0.75F。

        扩容步骤分为两步,首先创建一个新的Entry或Node数组,长度是原来的两倍;然后便利数组,把所有的节点重新Hash到新数组;由于长度扩大后,Hash的规则也会改变

 Java1.8中capacity默认大小为1<<4的原因:

        在初始化Map的时候,最好指定原始大小,而且最好是2的幂数,为了方便位运算,位与运算比算数计算效率高很多,之所以选择2的幂数,是为了实现均匀分布,length-1所有的二进制位全为1,只要HashCode本身分布均匀,拿hash算法的结果就是均匀的。

元素定位:

        get()方法通过hash计算找到元素所在的链表,然后通过equals方法进行比较确认,因此在重写equals方法时,最好重写hashcode方法,以保证相同的对象返回相同的hash值。

ConcurrentHashMap:

        在多线程的场景下,有Collections.synchronizedMap(Map),HashTable,ConcurrentHashMap三种方式线程安全;

Collections.synchronizedMap(Map):内部维护了一个普通的Map对象和排斥锁mutex:

在调用方法时传入一个Map和mutex,在操作map的时候,就会对方法上锁;

 HashTable:在操作数据的时候都会上锁,因此效率很低;

 CurrentHashMap:采用分段锁技术,内部维护了一个Segment数组,segment继承于ReentrantLock,每当一个线程占用锁访问Segment时,不会影响到其他的segnent;put数据时,先定位到Segment,再进行put操作,先尝试自旋,自旋次数达到MAX_SCAN_RETRIE则改为阻塞锁获取,保证能获取成功,JDK1.8之后,采用CAS+synchronized保证并发安全性;get定位到segment之后直接通过hash获取数据,不用加锁,因此效率很高;

Java8之后引入红黑树,当链表大于一定值之后转换为红黑树,默认是8;

size方法总体流程:

先采用乐观的方式统计,如果在两次记录的数量相同,则结束,如果不同再次尝试,再次不同则对所有的segment枷锁统计;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值