当前位置:首页 > IT技术 > 编程语言 > 正文

面试题-Java集合
2022-02-14 14:06:10

1. 常见的集合有哪些?

  • 答案
    • Collection接口的子接口包括:Set接口和List接口

    • Map接口的实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap以及Properties等

    • Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等

    • List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等


2. 常见的集合底层实现

  • 答案

    ArrayList底层是数组。

    LinkedList底层是双向链表。

    HashMap底层与HashTable原理相同,Java 8版本以后如果同一位置哈希冲突大于8则链表变成红黑树。

    HashTable底层是链地址法组成的哈希表(即数组+单项链表组成)。

    HashSet底层是HashMap。

    LinkedHashMap底层修改自HashMap,包含一个维护插入顺序的双向链表。

    TreeMap底层是红黑树。

    LinkedHashSet底层是LinkedHashMap。

    TreeSet底层是TreeMap。


3. HashMap与HashTable的区别?

  • 答案

    HashMap没有考虑同步,是线程不安全的;Hashtable使用了synchronized关键字,是线程安全的;

    HashMap允许K / V都为null;后者K / V都不允许为null。


4. ConcurrentHashMap和Hashtable的区别?

  • 答案

    ConcurrentHashMap结合了HashMap和HashTable二者的优势。HashMap没有考虑同步,HashTable考虑了同步的问题。但是HashTable在每次同步执行时都要锁住整个结构ConcurrentHashMap锁的方式是稍微细粒度的。


5. ConcurrentHashMap实现原理

  • 答案

    **JDK1.7 : 【数组(Segment) + 数组(HashEntry) + 链表(HashEntry节点)】
    **ConcurrentHashMap(分段锁) 对整个桶数组进行了分割分段(Segment),每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。

    Segment是一种可重入锁ReentrantLock,在ConcurrentHashMap里扮演锁的角色,
    HashEntry则用于存储键值对数据。

    JDK1.8 : Node数组+链表 / 红黑树
    利用CAS+Synchronized
    来保证并发更新的安全,底层依然采用数组+链表+红黑树的存储结构。


6. ArrayList和Vector的区别?

  • 答案

    Vector是线程安全的,ArrayList是线程不安全的。

    Vector在数据满时增长为原来的两倍,而ArrayList在数据量达到容量的一半时,增长为原容量的1.5倍。


7. ArrayList和LinkedList的区别?

  • 答案

    LinkedList基于双向链表的数据结构;ArrayList基于动态数组的数据结构。

    LinkedList在插入和删除数据时效率更高,ArrayList查询效率更高。


8. HashMap默认的初始化长度是多少?

  • 答案

    在JDK中默认长度是16,并且默认长度和扩容后的长度都必须是2的幂


9. 谈谈对HashMap构造方法中初始容量、加载因子的理解

  • 答案

    初始容量代表了哈希表中桶的初始数量,即Entry<K,V>[] table数组的初始长度

    加载因子是哈希表在其容量自动增加之前可以达到多满的一种饱和度百分比,其衡量了一个散列表的空间的使用程度,负载因子越大表示散列表的装填程度越高,反之愈小。


10. Java集合框架是什么?说出一些集合框架的优点?

  • 答案

    每种编程语言中都有集合,最初的Java版本包含几种集合类:Vector、Stack、HashTable和Array。随着集合的广泛使用,Java1.2提出了囊括所有集合接口、实现和算法的集合框架。在保证线程安全的情况下使用泛型和并发集合类,Java已经经历了很久。它还包括在Java并发包中,阻塞接口以及它们的实现。集合框架的部分优点如下:
    (1)使用核心集合类降低开发成本,而非实现我们自己的集合类。
    (2)随着使用经过严格测试的集合框架类,代码质量会得到提高。
    (3)通过使用JDK附带的集合类,可以降低代码维护成本
    (4)复用性和可操作性


11. 集合框架中的泛型有什么优点?

  • 答案

    Java1.5引入了泛型,所有的集合接口和实现都大量地使用它。泛型允许我们为集合提供一个可以容纳的对象类型,因此,如果你添加其它类型的任何元素,它会在编译时报错。这避免了在运行时出现ClassCastException,因为你将会在编译时得到报错信息。泛型也使得代码整洁,我们不需要使用显式转换和instanceOf操作符。它也给运行时带来好处,因为不会产生类型检查的字节码指令。


12. 为何Collection不从Cloneable和Serializable接口继承?

  • 答案

    Collection接口指定一组对象,对象即为它的元素。如何维护这些元素由Collection的具体实现决定。例如,一些如List的Collection实现允许重复的元素,而其它的如Set就不允许。很多Collection实现有一个公有的clone方法。然而,把它放到集合的所有实现中也是没有意义的。这是因为Collection是一个抽象表现。重要的是实现。

    当与具体实现打交道的时候,克隆或序列化的语义和含义才发挥作用。所以,具体实现应该决定如何对它进行克隆或序列化,或它是否可以被克隆或序列化。

    在所有的实现中授权克隆和序列化,最终导致更少的灵活性和更多的限制。特定的实现应该决定它是否可以被克隆和序列化。


13. Iterator是什么?

  • 答案

    Iterator接口提供遍历任何Collection的接口。我们可以从一个Collection中使用迭代器方法来获取迭代器实例。迭代器取代了Java集合框架中的Enumeration。迭代器允许调用者在迭代过程中移除元素。


14. Iterator和Listiterator之间有什么区别?

  • 答案

    (1)我们可以使用Iterator来遍历Set和List集合,而ListIterator只能遍历List。

    (2)Iterator只可以向前遍历,而LIstIterator可以双向遍历。

    (3)ListIterator从Iterator接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。


15. fail-fast与fail-safe有什么区别?

  • 答案

    Iterator的fail-fast属性与当前的集合共同起作用,因此它不会受到集合中任何改动的影响。Java.util包中的所有集合类都被设计为fail-fast的,而java.util.concurrent中的集合类都为fail-safe的。Fail-fast迭代器抛出ConcurrentModificationException,而fail-safe迭代器从不抛出ConcurrentModificationException。


16. hashCode()和equals()方法有何重要性?

  • 答案

    HashMap使用Key对象的hashCode()和equals()方法去决定key-value对的索引。当我们试着从HashMap中获取值的时候,这些方法也会被用到。如果这些方法没有被正确地实现,在这种情况下,两个不同Key也许会产生相同的hashCode()和equals()输出,HashMap将会认为它们是相同的,然后覆盖它们,而非把它们存储到不同的地方。同样的,所有不允许存储重复数据的集合类都使用hashCode()和equals()去查找重复,所以正确实现它们非常重要。
    equals()和hashCode()的实现应该遵循以下规则:

    (1)如果o1.equals(o2),那么o1.hashCode() == o2.hashCode()总是为true的。

    (2)如果o1.hashCode() == o2.hashCode(),并不意味着o1.equals(o2)会为true。


17. 我们能否使用任何类作为Map的key?

  • 答案

    我们可以使用任何类作为Map的key,然而在使用它们之前,需要考虑以下几点:

    1. 如果类重写了equals()方法,它也应该重写hashCode()方法。

    2. 类的所有实例需要遵循与equals()和hashCode()相关的规则。请参考之前提到的这些规则。

    3. 如果一个类没有使用equals(),你不应该在hashCode()中使用它。

    4. 用户自定义key类的最佳实践是使之为不可变的,这样,hashCode()值可以被缓存起来,拥有更好的性能。不可变的类也可以确保hashCode()和equals()在未来不会改变,这样就会解决与可变相关的问题了。


18. 如何决定选用HashMap还是TreeMap?

  • 答案

    对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择。然而,假如你需要对一个有序的key集合进行遍历,TreeMap是更好的选择。基于你的collection的大小,也许向HashMap中添加元素会更快,将map换为TreeMap进行有序key的遍历。


19. 哪些集合类提供对元素的随机访问?

  • 答案

    ArrayList、HashMap、TreeMap和HashTable类提供对元素的随机访问。


20. BlockingQueue是什么?

强引用
这种引用属于最普通最强硬的一种存在,只有在和 GC Roots 断绝关系时,才会被消掉。
软引用
软引用用于维护一些可有可无的对象。在内存足够的时候,软引用对象不会被回收,只有在内
存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会
抛出内存溢出异常。
可以看到,这种特性非常适合用在缓存技术上。比如网页缓存、图片缓存等。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾
回收,Java 虚拟机就会把这个软引用加入到与之关联的引用队列中。
弱引用
弱引用对象相比较软引用,要更加无用一些,它拥有更短的生命周期。当JVM进行垃圾回收
时,无论内存是否充足,都会回收被弱引用关联的对象。弱引用拥有更短的生命周期,在 Java
中,用 java.lang.ref.WeakReference 类来表示。它的应用场景和软引用类似,可以在一些对
内存更加敏感的系统里采用。
虚引用
这是一种形同虚设的引用,在现实场景中用的不是很多。虚引用必须和引用队列
(ReferenceQueue)联合使用。如果一个对象仅持有虚引用,那么它就和没有任何引用一
样,在任何时候都可能被垃圾回收。实际上,虚引用的 get,总是返回 null。

Java.util.concurrent.BlockingQueue是一个队列,在进行检索或移除一个元素的时候,它会等待队列变为非空;当在添加一个元素时,它会等待队列中的可用空间。BlockingQueue接口是Java集合框架的一部分,主要用于实现生产者-消费者模式。我们不需要担心等待生产者有可用的空间,或消费者有可用的对象,因为它都在BlockingQueue的实现类中被处理了。

Java提供了集中BlockingQueue的实现,比如ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue、SynchronousQueue等。

经常和线程池中的workQueue梦幻联动。


21. Collections类是什么?

  • 答案

    Java.util.Collections是一个工具类仅包含静态方法,它们操作或返回集合。它包含操作集合的多态算法,返回一个由指定集合支持的新集合和其它一些内容。这个类包含集合框架算法的方法,比如折半搜索、排序、混编和逆序等。


22. Comparable和Comparator接口有何区别?

  • 答案

    Comparable和Comparator接口被用来对对象集合或者数组进行排序。

    Comparable接口被用来提供对象的自然排序,我们可以使用它来提供基于单个逻辑的排序。
    Comparable接口实际上是出自java.lang包,它有一个compareTo(Object obj)方法用来排序。

    Comparator接口被用来提供不同的排序算法,我们可以选择需要使用的Comparator来对给定的对象集合进行排序。
    Comparator接口实际上是出自java.util包,它有一个compare(Object obj1, Object obj2)方法用来排序。


本文摘自 :https://www.cnblogs.com/

开通会员,享受整站包年服务立即开通 >