根据牛客网的面试经验的题进行的汇总,里面的内容是看别人的博客或者其东西进行汇总的,将这些的知识总结一下,方便自己查看和复习用
牛客网
集合(二)
JAVA集合
请解释为什么集合类没有实现Cloneable和Serializable接口?
像这些接口只要专注于自己的抽象功能即可,具体的实现操作则是由各自的实现类去完成的
请说明Java集合类框架的基本接口有哪些?
-
Collection
- List:有序的集合
- Set:无序且不重复的集合
-
Map:键值对,键不能重复
JAVA内存模型
请你说明一下ConcurrentHashMap的原理?
ConcurrentHashMap是将HashMap由线程不安全变为线程安全
-
JDK1.7
-
数组+Segment+分段锁
-
在JDK1.7中ConcurrentHashMap主要是由Segment组成,又因为Segment继承于ReentrantLock,所以每个Segment都有一把锁(分段锁),当访问不同分段锁中的数据时,不会相互影响
-
static class Segment<K, V> extends ReentrantLock implements Serializable
-
定位一个元素要两次hash,第一次hash定位到Segment,第二次hash定位到元素所在链表的头部
-
-
JDK1.8
-
数组+链表+红黑树(数组容量>64 && 链表长度>8)【红黑树的查找能力O(logn)】
-
class Node<K,V> implements Map.Entry<K,V> { final int hash;//key的hash值 final K key;//key值 volatile V val;//value(保证可见性) volatile Node<K,V> next;//下一个节点(保证可见性) }
-
ReentrantLock 与synchronized区别
- ReentrantLock又叫可重入锁,同时还支持获取锁的公平和非公平性选择
- 公平性:是指当线程a进行访问时,此时内部有个计数器num+1,如果此时来了线程b,c那么就是处在等在状态,(此时b处于待唤醒状态),当a再次请求资源,计数器变加1变为num=2,可以不用排队,直接使用,使用完后释放所有锁时num=0,此时唤醒b
- 非公平性:当a使用资源时,b等待,a使用完资源释放后,此时c获取请求,竞争资源,c抢占成功,b继续等待。非公平锁根据每个线程对资源的强制能力来获取资源
- synchronized:当a使用资源时,b等待,a使用完资源释放后,b才能使用
请解释一下TreeMap?
key不能为null
-
是一个BST
-
根结点和Null都是黑色的
-
如果一个子结点是红色的,那么它的子结点一定是黑色的,其父结点也是黑色的
-
结点要么是黑色的要么是红色的
public class TreeMap<K, V> extends AbstractMap<K, V> implements NavigableMap<K, V>, Cloneable, Serializable
private final Comparator<? super K> comparator;//私有比较器
private transient TreeMap.Entry<K, V> root;//根节点
private transient int size = 0;//长度
private transient int modCount = 0;
private transient TreeMap<K, V>.EntrySet entrySet;
private transient TreeMap.KeySet<K> navigableKeySet;
private transient NavigableMap<K, V> descendingMap;
private static final Object UNBOUNDED = new Object();
private static final boolean RED = false;
private static final boolean BLACK = true;
private static final long serialVersionUID = 919286545866124006L;
-
其内部都是Entry
-
TreeMap.Entry
-
static final class Entry<K, V> implements java.util.Map.Entry<K, V> { K key; V value; TreeMap.Entry<K, V> left;//左结点 TreeMap.Entry<K, V> right;//右结点 TreeMap.Entry<K, V> parent;//父结点 boolean color = true;//默认为黑色 }
-
Map.Entry
-
public interface Entry<K, V> { K getKey();//获取key V getValue();//获取value V setValue(V var1);//设置value boolean equals(Object var1); int hashCode(); }
TreeMap是对封装好的Entry进行操作
- Map.Entry
- getValue() setValue(V value) getKey() equals() hashCode()
- TreeMap.Entry
- isEmpty() Comparator() put()
- put()是给TreeMap中添加元素
- 首先判断root是否为空
- 为空,直接添加新结点,size++
- 不为空
- 看比较器是否存在
- 存在,调用比较,<0,指向左边
- 否则,指向右边;<=0时,即key相同,setValue
- 不存在
- 创建Comparable;比较同理
- 看比较器是否存在
- 首先判断root是否为空
- put()是给TreeMap中添加元素
- isEmpty() Comparator() put()
集合
请说明ArrayList是否会越界?
在添加元素时会有下标越界
请你说明concurrenthashmap有什么优势以及1.7和1.8区别?
因为hashMap在并非情况下是不安全的,但是concurrenthashmap在并发状况下时安全的
- 1.7
- 数组+链表+分段锁
- 当进入不同的Segment时,不会有影响,这就是分段锁
- 1.8
- 数组+链表+红黑树(容量>64&&长度>8)
- 当链表的长度过长,性能会下降,所以此时采用红黑树
请你说明一下TreeMap的底层实现?
- put()
- 首先定义一个var3指向root
- 先判断root是否存在,不存在,创建一个;存在—>判断比较器是否为空,不为空,比较,判断返回值大小,<0,var3=var3.left,否则var 3=var3.right,若相等,更新value—>比较器为空,先创建Comparable,后面同理
请你说明ConcurrentHashMap锁加在了哪些地方?
key和value都不能为null
- JDK1.7中的Segment数组继承ReetrenLock,锁的是每一个Segment数组,当访问的数据不在同一个Segment中,则不会发生冲突
- JDK1.8用CAS和synchronized保证线程并发
请你解释HashMap的容量为什么是2的n次幂?
通过tab[i = (n - 1) & hash]公式计算得出hash值,在进行&运算时,产生的冲突较少,可以用16和15来和0-10(hash值)进行&运算,看其hash值与原来的hash值发生冲突的概率
请你简单介绍一下ArrayList和LinkedList的区别,并说明如果一直在list的尾部添加元素,用哪种方式的效率高?
- ArrayList
- 是动态数组的数据结构
- 对于查询元素更加高效
- LinkedList
- 是双向链表的数据结构
- 对于插入和删除元素更加高效
如果一直在尾部添加元素,用LinkedList更加高效
如果hashMap的key是一个自定义的类,怎么办?
要重写hashcode()和equals()
请你解释一下hashMap具体如何实现的?
- 先计算key的hash值,如果没有一样的,直接将value插入
- 如果有一样的hash值,将其value以链表或红黑树的形式插入
请你说明一下Map和ConcurrentHashMap的区别?
hashMap和ConcurrentHashMap区别
- hashMap在多线程的情况下是不安全的
- ConcurrentHashMap在JDK1.8中用CAS和synchronized来保证线程并发下的安全,并且在1.8中是通过数组+链表+红黑树实现的