linkedlist和ArrayList的区别?
ArrayList是数组的结构,LinkedList是基于链表的结构
基于此:
LinkedList基于索引来实现随机查询,ArrayList是基于链表的遍历,所以在随机读取的性能上,A是要比L强的,也正因为链表的原因,LinkedList的增删是比ArrayList要快速的,因为在链表中只需要将前后节点的头尾改一下就好,不需要像ArrayList一样进行数据的前后移动。
HashMap原理?java8做了什么改变?
HashMap底层是基于数组+链表+红黑树的结构,存储的是K-V键值对,Key是唯一的,Value是可以重复的,总的是基于HashCode()来判断数据存放的位置,当一个K-V键值对put进HashMap的时候,首先会进行HashCode的计算,通过Hashcode来判断存放的桶位,此处的判断是基于位运算代替了原本的取模运算,以此来提高速度,但必须是在2的次幂下才能满足,所以HashMap的长度是2的次幂的原因就在于此。
Hashcode不能保证不发生hash碰撞,在发生Hash碰撞的时候,HashMap就会通过链表来解决,发生冲突就放在链表里面,如果链表的长度大于8就会自动转化为红黑树,红黑树在链表长度小于6的时候会自动退化为链表。在第一次new HashMap的时候创建的长度是0,只有第一次put的时候长度才会默认设置为16,默认加载因子是0.75,这是时间和空间上的一个折中选择,当put完之后会检查是不是大于12,大于的话会进行数组扩容,扩容为原来的两倍。
java8 后是将数组+链表升级为了数组+链表+红黑树,并且是将头插法改为了尾插法,头插法的在多线程下进行扩容的时候,会将数据插入到头部,导致原有数据的位置发生改变,可能形成环形链表,导致死循环,这也是1.7上面HashMap线程不安全的一个原因,但1.8改为尾插法也并没有完全解决HashMap不安全的问题,因为它的put和get方法也是没有加锁的,在多线程下依然会发现线程不安全的情况。
HashMap,HashTable,ConcurrentHashMap的共同点和区别
共同点的话都是K-V键值对类型的数据,都是基于数组+链表+红黑树的。
HashMap:
线程不安全
K可以为NULL,V可以为NULL
初始容量为16,加载因子为0.75
HashTable:
线程安全,但是是靠Synchronized实现的重量级锁,性能比较差
K不可以为NULL,V不可以为NULL
初始容量为11
ConcurrentHashMap:
线程安全,但是是靠分段锁实现的线程安全,1.7之前是Segment分段来控制HashEntry,每一个Segment继承RetrenLock,要修改对应的HashEntry需要先获得对应的Segment锁
K不可以为NULL,V不可以为NULL
JDK8为何又放弃分段锁,是因为多个分段锁浪费内存空间,竞争同一个锁的概率很低,效率低,1.8之后去掉了segment,直接用Volatile修饰对应的table,锁的粒度更小,因此获得了更高的效率,并使用CAS操作来确保Node的一些操作的原子性,取代了锁。
ArrayList中删除数据?
使用正向fori循环删除的话,会导致重复的元素没有被删除,反向的话是可以正常删除的。
foreach的话,因为没有进行modcount的同步,会报错
建议使用Itertor迭代器进行遍历删除
TreeMap的介绍
TreeMap的话,底层是红黑树,如果没有指定比较器的话,会按照Key自然排序的
HashMap为什么线程不安全?
在1.7中,HashMap采用的是头插法,也就是说当有数据插入时,比如同一链表上的A,一会又进来个B,这个时候头插法会将B的next指向A,如果来了C,C的next指向B,而C在头节点上,如果多线程下,恰好进行扩容,T1和T2两个线程又刚好进了resize(),进了transfer()进行扩容,因为头插法的缘故,会把链表的顺序打乱,即本来获取到的next位置都不对了,T1扩完容,T2也会进行扩容,此时就会形成环链,也就是A的next指向B,B的next指向A,因此线程不安全。
而在1.8中,采用的是尾插法,不会改变链表的顺序,但是put和get仍然没有加锁,还是线程不安全,put的时候,两个线程同时拿到了一个桶位,然后T1放置K-V,结束后T2因为已经判断过桶位了,直接再次放置,会把前面的覆盖掉。
HashSet是如何保证不重复的
因为HashSet就是HashMap的K,v都为null,所以保证了不重复。
List的排序
通过比较器
Collections.sort(arrayList, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.length()-o1.length();
}
});
重写compare方法
垃圾回收