1、HasMap的存储和获取原理

调用put()方法传递键和值来存储时,先对键调用hashCode()方法,返回的hashCode用于找到bucket位置来储存Entry对象,也就是找到了该元素应该被存储的桶中(数组)。当两个键的hashCode值相同时,bucket位置发生了冲突,也就是发生了Hash冲突,这个时候,会在每一个bucket后边接上一个链表(JDK8及以后的版本中还会加上红黑树)来解决,将新存储的键值对放在表头(也就是bucket中)。

当调用get方法获取存储的值时,首先根据键的hashCode找到对应的bucket,然后根据equals方法来在链表和红黑树中找到对应的值。

2、解决Hash冲突的方法有哪些?

  • 拉链法 (HashMap使用的方法)
  • 线性探测再散列法
  • 二次探测再散列法
  • 伪随机探测再散列法

3、哪些类适合作为HashMap的键?

String和Interger这样的包装类很适合做为HashMap的键,因为他们是final类型的类,而且重写了equals和hashCode方法,避免了键值对改写,有效提高HashMap性能。
为了计算hashCode(),就要防止键值改变,如果键值在放入时和获取时返回不同的hashCode的话,那么就不能从HashMap中找到你想要的对象。

4、ConcurrentHashMap的具体实现方式(分段锁)

该类包含两个静态内部类MapEntry和Segment,前者用来封装映射表的键值对,后者用来充当锁的角色。

Segment是一种可重入的锁ReentrantLock,每个Segment守护一个HashEntry数组里得元素,当对HashEntry数组的数据进行修改时,必须首先获得对应的Segment锁。

5、TreeMap有哪些特性?

TreeMap底层使用红黑树实现,TreeMap中存储的键值对按照键来排序

  • 如果Key存入的是字符串等类型,那么会按照字典默认顺序排序
  • 如果传入的是自定义引用类型,比如说User,那么该对象必须实现Comparable接口,并且覆盖其compareTo方法;或者在创建TreeMap的时候,我们必须指定使用的比较器。

6、Comparable接口和Comparator接口有哪些区别呢?

  • Comparable实现比较简单,但是当需要重新定义比较规则的时候,必须修改源代码,即修改User类里边的compareTo方法
  • Comparator接口不需要修改源代码,只需要在创建TreeMap的时候重新传入一个具有指定规则的比较器即可。

7、ArrayList和LinkedList有哪些区别?

常用的ArrayList和LinkedList的区别总结如下。

  • ArrayList底层使用了动态数组实现,实质上是一个动态数组
  • LinkedList底层使用了双向链表实现,可当作堆栈、队列、双端队列使用
  • ArrayList在随机存取方面效率高于LinkedList
  • LinkedList在节点的增删方面效率高于ArrayList
  • ArrayList必须预留一定的空间,当空间不足的时候,会进行扩容操作
  • LinkedList的开销是必须存储节点的信息以及节点的指针信息

多线程环境下,我们可以使用CopyOnWriteArrayList替代ArrayList来保证线程安全。

8、HashSet和TreeSet有哪些区别?

 HashSet和TreeSet的区别总结如下。

  • HashSet底层使用了Hash表实现。

保证元素唯一性的原理:判断元素的hashCode值是否相同。如果相同,还会继续判断元素的equals方法,是否为true

  • TreeSet底层使用了红黑树来实现。

保证元素唯一性是通过Comparable或者Comparator接口实现