Java基础-三大集合(TODO一致性哈希

1. List,Set,Map区别

答:首先Map和Collection是并列的上层接口,List和Set是Collection的子接口。

  • List(解决顺序问题):存储一组有序可重复的对象,实现类有ArrayList、LinkedList和Stack等。
  • Set(元素独一无二):不存在重复的元素,实现类有HashSet、TreeSet等。
  • Map(Key值搜索):键值对存储,Key值不能重复,但能引用相同的对象,实现类有HashMap、ConcurrentHashMap等。

2. HashMap和HashTable的区别

答:从4个方面作答。

  • 线程安全:HashMap线程不安全;HashTable内部使用synchronized关键字,线程安全。
  • Null Key支持:HashMap中null可作为Key;HashTable中null不能作为key也不能作为value。
  • 效率:HashMap比HashTable效率高一点,而且HashTable基本淘汰了。
  • 底层数据结构:JDK1.8之后HashMap在链表长度大于8时,将链表转为红黑树,以减少搜索时间。

2.1 HashMap线程不安全的解析

答:解释HashMap和HashTable。

  • HashMap线程不安全是因为多线程环境下扩容可能会造成死循环。
  • HashTable线程安全是因为内部实现put和remove方法时使用synchronized同步,所以对单个方法的使用是线程安全的。但对多个方法复合操作时,无法保证安全性。

2.2 Java集合中的快速失败机制

答:快速失败(fast-fail)时Java集合中的错误检测机制,当多个线程对集合进行结构层面的改变操作时,可能触发此机制。底层是通过迭代器遍历下一个元素之前都会检测modCount变量是否为exceptedModCount值,不是就抛出异常。

2.3 HashMap的底层结构

答:JDK1.8之后使用数组+链表+红黑树实现,解决链表过长而查询速度变慢。
在这里插入图片描述

2.4 HashMap的初始容量、加载因子、扩容增量和扩容步骤

答:HashMap的初始容量16,加载因子0.75,扩容增量是原容量的1倍。含义是HashMap中的元素个数超过16*0.75=12个后进行扩容。将创建原来HashMap大小两倍的bucket数组,将原来的对象放入新的bucket数组中,即rehash。

2.5 HashMap的长度为什么是2的幂

答:有助于减少碰撞次数,提高查询效率。 hash%length==hash&(length-1)的前提是 length 是2^n。例子:length为15,则length-1为14,对应二进制为1110,进行与操作后,最后一位为0,则最后一位为1的位置都不能存放元素。

2.6 Hash冲突解决办法

答:拉链法,线性探测再散列,二次探测再散列,伪随机探测再散列。

2.7 一致性哈希

TODO

3. ConcurrentHashMap和Hashtable的区别

答:主要体现在线程安全的方式上。

  • 底层数据结构:ConcurrentHashMap是数组+链表/红黑树,Hashtable是数组+链表。
  • 实现线程安全:
  1. 在JDK1.8之前,ConcurrentHashMap使用分段锁将Hash表分割为16个桶,每一把锁只锁当前操作用上的桶。
    在这里插入图片描述
  2. 在JDK1.8之后,使用Node数组+链表+红黑树的数据结构,并发控制用synchronized和CAS操作。
    在这里插入图片描述
  • Hashtable使用synchronized保证线程安全,即用同一把锁来保护访问操作。

4. TreeMap特性

答:TreeMap底层使用红黑树实现,存储的键值按键排序。

  • Key值存的是字符串等基础类型,按字典序排序
  • Key值存的是自定义类型,需要类对象实现Comparable接口,并重写compareTo方法;或者创建TreeMap时指定比较器。
// 方式一:定义该类的时候,就指定比较规则
class User implements Comparable{
    @Override
    public int compareTo(Object o) {
        // 定义比较规则
        return 0;
    }
}
public static void main(String[] args) {
    // 方式二:创建TreeMap的时候,可以指定比较规则
    new TreeMap<User, Integer>(new Comparator<User>() {
        @Override
        public int compare(User o1, User o2) {
            // 定义比较规则
            return 0;
        }
    });
}

4.1 Comparable和Comparator的区别

答:总结为:

  • comparable接口在java.lang包,自定义比较规则时必须重写compareTo方法。
  • comparator接口在java.util包,在创建TreeMap时需要传入一个自定义规则的比较器。

5. ArrayList和LinkedList区别

答:总结如下:

  • 底层数据结构:ArrayList底层是Object动态数组;LinkedList底层使用双向链表。
  • 快速随机访问:ArrayList支持随机访问(相当于get(int index)方法);LinkedList不支持。
  • 内存空间占用:ArrayList必须预留一定的空间;LinkedList要存储前驱后继和节点信息,开销大。
    注:ArrayList和LinkedList都是非线程安全的,Vector保证线程安全所有方法都是同步,但耗费大量时间,基本被抛弃了。

6. HashSet,HashMap和TreeSet区别

答:总结如下:

  • HashSet底层使用Hash表实现,通过元素的hashCode值和equals()方法保证元素唯一性;
  • TreeSet底层使用红黑树实现,通过comparable或comparator接口保证元素唯一性;
  • HashSet底层是基于HashMap实现的,基本都是调用hashmap的方法。

7. LinkedHashMap和LinkedHashSet

答:LinkedHashMap能记录元素的插入顺序和访问顺序。具体实现:内部通过双向链表,保证元素的插入顺序。内部使用LRU(最近最少使用)算法。LinkedHashSet底层使用LinkedHashMap实现,二者关系类似HashMap和HashSet。

8. Iterator和ListIterator区别

答:这两种迭代器区别如下:

  • Iterator能遍历list和set集合;ListIterator只能遍历list集合。
  • Iterator只能后向遍历;ListIterator前向后向都可。
  • ListIterator也是继承了Iterator,再添加新的功能。

9. 数组和List的转换

答:Arrays.asList和List.toArray方法。注意事项:

  • Arrays.asList转换后,不能修改集合,因为转化后本质上仍属一个数组,是Arrays内部的ArrayList类。
  • List.toArray转换,无参方法默认返回值是Object[]类,有参方法应传入list.size()即list大小的数组,以防止预留的空间大小不够被重新分配内存空间。
发布了71 篇原创文章 · 获赞 3 · 访问量 2436

猜你喜欢

转载自blog.csdn.net/qq_34761012/article/details/104199039