Java集合框架面试题

作者: outSiderYN | 来源:发表于2017-04-03 08:43 被阅读1982次

标签(空格分隔): Java集合框架


屏幕快照 2017-04-03 上午8.41.30.png 屏幕快照 2017-04-03 上午8.42.10.png

面试题汇总

1. 什么是Java集合框架?请列举出集合(Collections framework)框架的一些好处?

屏幕快照 2017-04-03 上午7.45.45.png-101.1kB屏幕快照 2017-04-03 上午7.45.45.png-101.1kB
  • 通过使用集合框架的核心类可以减少开发成本,从而避免实现自己的集合类。
  • 使用经过良好测试的集合类可以提高代码的质量。
  • 使用JDK自带的集合类可以减少代码维护成本。
  • 良好的可读性和通用性。

2. 集合框架(Collections framework)中的泛型有什么好处?

泛型是Java 1.5中的新特性,所有的集合接口和实现类都大量地使用了泛型。泛型允许我们指定集合中对象的类型,因此试图向其中添加其他类型的元素时在编译期就会报错。这样就避免了运行时的ClassCastException异常并且我们不再进行类型转换和 instanceof判断,我们的代码更简洁了。此外有了泛型,也不会生成用于类型检查的字节码了,提高了运行时效率。

3. 列举出Java集合框架的一些基本接口?

  • Collection是集合层次中的顶层接口。一个集合代表了一组对象。Java 平台不提供这个接口的任何实现。
  • Set 是一种不能包含重复元素的集合。这个接口是对数学概念中的集合的一个抽象,用于表示某类事物的集合,如可以表示一副扑克牌。
  • List 是一种有序的集合,可以包含重复的元素。可以通过索引访问元素,就像一种动态的数组。
  • Map 是一种将key映射到value的集合。map对象不能包含重复的key:每个key至多可以映射到一个value。
  • 还有一些其他的接口,如Queue,Dequeue,Iterator,SortedSet,SortedMap和ListIterator.

4. 为什么集合(Collection)不能继承Cloneable和Serializable接口?

Collection 接口将一组对象作为它的元素。然而元素是由具体的实现类来维护的。例如,List允许重复元素,而其他的实现类如Set并不允许这样做。许多 Collection接口的实现类都有一个public的clone()方法。但不是所有的实现类都包含此方法。因为Collection接口是一种抽象 的表示方法,表示的是一种契约、约定,对外暴露的“服务”,具体的实现类才有意义。对于cloning和serializing这些语义性的方法只有放到 具体的实现类中才有意义,也就是说,具体的实现类才能决定它是否应该被clone或serialized,甚至是它能否被clone或 serialized。
因此强制在所有的实现类中实现clone和serialization都会让灵活性降低并产生更多的局限性。具体的实现类才能决定它是否可以被clone或serialized。

5. 为什么Map接口不能继承Collection接口?

尽管Map接口及其实现类是Collection框架的一部分,但是要注意的是Map不是集合,集合也不是Map。因此Map继承Collection接口是无意义的,反之亦然。
如果Map接口继承了Collection接口,那么元素如何存放呢?Map保存的是键值对,提供了取得所有key或value集合的方法,但它体现不了“元素的集合”这种概念。

6. 什么是迭代器(Iterator)?

JDK1.8官方文档

An iterator over a collection. Iterator takes the place of Enumeration in the Java Collections Framework. Iterators differ from enumerations in two ways:
Iterators allow the caller to remove elements from the underlying collection during the iteration with well-defined semantics.
Method names have been improved.

Iterator接口提供了用于遍历集合的方法。可以在集合对象上调用iterator()方法来获取一个迭代器的实例。Java集合框架中,Iterator接口取代了Enumeration接口,并且,迭代器允许在进行遍历时移除元素。

7. Enumeration和Iterator接口有何不同?

Enumeration的速度是Iterator的2倍并且消耗较少的内存, 它很简单,适合在基本需求(basic needs)下使用。但是相对于Enumeration,Iterator更安全,因为在对集合进行遍历时会阻止其他线程对集合进行修改。
Java集合框架中, Iterator取代了Enumeration。Iterator允许从集合中移除元素,而这对Enumeration来说是不可能的。而且Iterator接口中的方法名清晰明了,一看就知道是干什么用的。

8. 为什么没有类似Iterator.add()这样的方法来向集合中添加元素?

如果迭代器无法保证迭代的顺序,那么这种说法是不清晰的(unclear)。注意的是,ListIterator就提供了add()方法,因为它能保证迭代的顺序。

9. 为什么Iterator没有一个方法在不移动指针情况下直接获取下一个元素?

这可以在当前的Iterator接口之上进行实现,但是由于这种使用情况很少,所以把它包含在接口中几乎是无意义的,想要这种功能,自己实现即可。

10. Iterator与ListIterator有何不同?

  • Iterator可以用来遍历Set和List集合,而ListIterator只能用于遍历List。
  • Iterator只能进行正向(forward direction)遍历而ListIterator可以双向遍历。
  • ListIterator继承于Iterator接口,但却添加了一些额外的功能,如添加、替换元素,获取前后元素的索引。

11. 迭代一个list有哪些不同的方法?

有两种方式:使用迭代器或用for-each循环。

List<String> strList = new ArrayList<String>();
//using for-each loop
      for(String obj : strList){
          System.out.println(obj);
      }
//using iterator
      Iterator<String> it = strList.iterator();
      while(it.hasNext()){
          String obj = it.next();
          System.out.println(obj);
      }

使用iterator 是线程安全的,因为它会确保在遍历时集合没有被修改,否则会抛出ConcurrentModificationException异常。

12. 对iterator的快速报错(fail-fast)特性有何理解?

Iterator 的快速报错机制会在每次取下一个元素时检查集合是否发生了修改。若发现有修改,那么就抛出 ConcurrentModificationException异常。除了像 ConcurrentHashMap,CopyOnWriteArrayList这样的并发集合类,所有集合类的迭代器都是按fail-fast这种机制 进行实现的。

13. fail-fast与fail-safe的区别是什么?

Iterator的fail- safe是对集合在进行clone时提供的一种保护机制,因此集合发生了修改不会引起任何问题。从设计上来说,java.util包中的集合类都是 fail-fast机制的,而java.util.concurrent包中的集合类都是fail-safe的。Fail-fast机制实现的 iterator会抛出ConcurrentModificationException异常,而fail-safe机制的iterator永远不会抛出 ConcurrentModificationException异常。

14. 在迭代一个集合时如何避免ConcurrentModificationException?

可以使用并发集合类来遍历集合从而避免ConcurrentModificationException异常。例如, 使用CopyOnWriteArrayList 来替代 ArrayList.

15. 为什么Iterator接口没有具体的实现?

Iterator 接口只是用于声明迭代集合的方法,但它的实现是依赖于具体的类的。 每个集合类都通过嵌套类的方式实现了自己的Iterator接口从而返回用于遍历的iterator对象。这样可以让集合类自己选择迭代器的实现是 fail-fast还是fail-safe机制。例如,ArrayList的迭代器就是fail-fast,而CopyOnWriteArrayList 的迭代器则是fail-safe的。

16. 什么是UnsupportedOperationException?

UnsupportedOperationException 一种用于指示当前对象不支持调用某种方法的异常。JDK中广泛地使用了这种异常,在集合框架中,如果是通过 java.util.Collections.UnmodifiableCollection()方法创建的集合,那么对集合对象调用add()或 remove()方法都会抛出此异常。

17. Java中HashMap的工作原理?

18. hashCode()和equals()方法的意义?

HashMap 会调用key对象的hashCode() 和equals() 方法来决定”键值对”的索引位置。当从HashMap中取值时这两个方法也会被调用。如果这两个方法不能正确地实现的话,那么对于两个不同的 key,hashCode()和equals()方法也许会产生相同的的输出,从而不会将它们存放到不同的位置了,HashMap将它们看作一样的,因此 一个对象会被另一个覆盖。同理,其他哪些不允许存放重复元素的集合类都回调用hashCode()和equals()方法来判断元素是否重复,因此,正确 地实现这两个方法是非常重要的。要实现它们,请遵循以下原则:

If o1.equals(o2), 那么o1.hashCode() == o2.hashCode()总为真。
If o1.hashCode() == o2.hashCode()为真, 并不意味着 o1.equals(o2)也为真。

19. 可以用任意类型来作为Map的key吗?

Map允许使用的任意的类型作为 Key,然而在使用前请仔细考虑以下方面:

  • 如果类重写了equals()方法,那么它也应该重写hashCode()方法。
  • 类应总是遵循与equals() 和hashCode()相关的那些规则,具体请看上一个问题。
  • 如果类中的某个字段并没有在equals()方法中使用,那么它也不应该出现在hashCode()方法中。
  • 如果用户想要用自己的类来做Map的键时,最好能确保key是不可变的(immutable),这样hashCode()方法就会对其进行缓存从而提高性 能。并且不可变的类型也会确保在运行时hashCode() and equals()方法的值出也不会改变,从而避免不必要的麻烦。

20. Map接口中提供了哪些与Collection类不同的方法?

  • Set keySet(): 返回map中key的集合。这个集合是与map相关联的,因此任何对map的修改都会反应到set上,反之亦然。如果在迭代集合时map被修改了(除了用 迭代器的remove()方法),那么迭代的结果是未定义的(undefined)。 set支持移除操作,所以可以通过Iterator.remove, Set.remove, removeAll, retainAll方法来删除“键”,同时map中的键值对也会被删除。但set不支持add()或 addAll()方法。
  • Collection values(): 返回map中value的集合。这个集合也是与map相关联的,任何对map的修改都会反应到set上,反之亦然。如果在迭代集合时map被修改了(除了 用迭代器的remove()方法),那么迭代的结果是未定义的(undefined)。 set支持移除操作,所以可以通过Iterator.remove, Collection.remove, removeAll, retainAll,clear方法来删除“值”,同时map中的键值对也会被删除。但set不支持add()或 addAll()方法。
  • Set<Map.Entry<K, V>> entrySet(): 返回map中键值对的集合。这个集合也是与map相关联的,任何对map的修改都会反应到set上,反之亦然。如果在迭代集合时map被修改了(除了用迭 代器的remove()方法或setValue()方法),那么迭代的结果是未定义的(undefined)。set支持移除操作,所以可以通过 Iterator.remove,Set.remove, removeAll, retainAll,clear方法来删除“键值对”。但set不支持add()或 addAll()方法。

21. HashMap与Hashtable有何区别?

HashMap 和 Hashtable 都实现了Map接口,看起来很相似,但它们之间有如下的区别:

  • HashMap的键值均可为null,而Hashtable不允许键或值为null。
  • Hashtable是synchronized的 而HashMap 则不是同步的。因此,HashMap适用于单线程环境下,Hashtable适合在多线程环境下使用。
  • Java 1.4中引入LinkedHashMap作为HashMap的子类,因此可以进行有序的迭代,并且可以很轻松的从 HashMap 过渡到 LinkedHashMap,然而 Hashtable的迭代顺序是无法预测的。
  • HashMap 可以对Key的集合进行迭代因此受fail-fast机制保护,而Hashtable只提供了键的Enumeration,因此无法实现这样的机制。
  • Hashtable是一种比较基础的类,如果想在迭代时对map进行修改,那么应该使用 ConcurrentHashMap。

22. 怎样决定何时使用HashMap何时使用TreeMap?

对 于插入、删除、定位元素频繁的操作,HashMap提供了最好的效率。如果想要按key的排序来遍历,那么TreeMap是不二选择。某些情况下,依赖集 合的大小,先向HashMap中添加元素,然后转换为TreeMap再按key的排序进行遍历也许会带来效率上的提高。

23. ArrayList和Vector的相同点和不同点?

  • Vector 是同步的而ArrayList不是同步的。如果想要在迭代list时对其进行修改,那么应该选用CopyOnWriteArrayList类。
  • ArrayList 比 Vector 的速度快,因为它没有同步问题带来的等待。
  • ArrayList 是个多面手,因为我们可以很容易的通过使用Collections工具类来获得新的同步的list或只读的(read-only)。
  • 两个类都是基于索引访问的并且在内部都是通过数组保存元素。
  • 两个类都按插入顺序来维护元素顺序,从而可以按插入顺序来获取元素。
  • 它们的迭代器都按fail-fast机制进行实现。
  • ArrayList Vector 都允许插入null,并且可以按索引进行随机访问。

24. Array和ArrayList的区别?哪些情况下优先选择Array而不是ArrayList?

  • Array 可以包含基本类型或对象类型的元素,而ArrayList 只能包含对象类型的元素。

  • Array 大小是固定的而 ArrayList 大小是动态的。

  • Array 不像ArrayList那样提供很多特性,如addAll, removeAll, iterator方法等等。尽管大多数情况下我们都使用ArrayList,可是在少数情况下Array也是一个不错的选择,情况如下:

  • 如果list的大小固定并且大多数情况是用于存储和遍历集合。

  • 如果list中要包含基本类型的数据,那么Array是不错的选择,尽管Collections使用自动装箱机制会简化我们的代码量,但它的效率仍不如具有固定大小的可以包含基本类型的Array。

  • 如果要操作多维的数据,那么使用[][]要比List<List<>>容易的多。

25. ArrayList和LinkedList的区别?

  • ArrayList 是一种基于索引的数据结构,底层是以Array来实现的,因此可以随机访问其中的元素,性能为 O(1) ,但LinkedList 是以链表的方式来存储数据的,每个节点都首尾相连。因此尽管有按索引取回元素的方法,但其内部实现还是从头遍历,然后返回元素,因此其性能是O(n),比 ArrayList要慢。
  • 相对于ArrayList,LinkedList在插入,添加或删除元素时就快得多了,因为LinkedList的实现不依赖数组,向集合中间添加元素时就不会有自动扩容和更新索引的麻烦了,所以速度要快。
  • LinkedList比ArrayList占用更多的内存,因为LinkedList中的每个节点都存储着前后元素的引用。

26. 哪些集合(collection)类提供了随机访问元素的功能?

ArrayList, HashMap, TreeMap, Hashtable 类都具有随机访问元素的特性。

27. 什么是EnumSet?

java.util.EnumSet 是对Set接口的一种实现,使用了枚举(enum)类型。 All of the elements in an enum set must come from a single enum type that is specified, explicitly or implicitly, when the set is created. EnumSet不是同步的,null不允许添加进去。它也提供了一些有用的方法,如copyOf(Collection c), of(E first, E… rest) 和 complementOf(EnumSet s)。

28. 哪些集合(collection)类是线程安全的?

Vector, Hashtable, Properties and Stack都是同步的(synchronized)类,因此是线程安全的,可以在多线程环境下使用. Java 1.5 Concurrent API 引入了一些允许在迭代过程中可以修改集合的并发类,由于它们会在迭代时会clone一份集合,所以在多线程环境下也是安全的。

29. 并发集合(concurrent Collection)类有哪些?

Java 1.5 Concurrent包(java.util.concurrent) 引入了线程安全的集合类,允许在迭代时对集合进行修改。这些类的迭代器都是按fail-fast机制进行实现的,会抛出 ConcurrentModificationException异常。常见的类有 CopyOnWriteArrayList,ConcurrentHashMap,CopyOnWriteArraySet等等。

30. 什么是BlockingQueue?

java.util.concurrent.BlockingQueue 是Queue接口的子接口,支持获取元素时等待队列变为非空,以及存储元素时等待空间变得可用。BlockingQueue接口是java集合框架的一部 分,它主要用于处理生产者、消费者问题。对于生产者不必再关心是否还有存储空间,对于消费者不必再关心是否有对象可以消费,所有这些细节都由具体的实现类 处理了。BlockingQueue接口有几个实现类,如ArrayBlockingQueue, LinkedBlockingQueue, PriorityBlockingQueue, SynchronousQueue等等。

31. 什么是Queue,Stack以及它们的区别?

Queue 和Stack 都是用于存储临时数据的。java.util.Queue是一个接口,其实现类大多位于concurrent包中。 Queue 可以按FIFO的顺序取回元素,但并不是所有的queue都遵循这个原则。如Deque接口就可以从队列的两端访问元素。
Stack 与 queue 类似,但它是按LIFO的顺序访问元素。
Stack是一个类,继承了Vector类,而Queue只是一个接口。

32. Collections类有什么作用?

java.util.Collections 是一个工具类(utility),有许多用于操作、返回集合的静态方法。 它包含了对集合操作的各种算法,其中较常见的是“包装器(wrappers)”,可以根据指定的集合返回一个新集合,还有许多其他的一些零碎的用法这里不 再赘述。这个类实现了许多针对集合操作的算法,如二叉搜索、排序、洗牌(shuffling)、逆序(reverse)等等。

33. 怎样理解Comparable, Comparator 接口?

如 果想要调用Array或Collection类的排序方法,那么任何自定义类都需要实现Comparable接口。排序方法会调用Comparable 接口中的compareTo(T obj) 方法。我们要重载此方法,以返回负整数,0,正整数来表示当前对象(this)是否小于,等于或大于传进来的对象。但是,在实际的应用中,我们通常有基于 不同的参数进行排序的需求。例如,CEO想要按职工的薪水进行排序,而HR希望按年龄进行排序。在这种情况下,我们就需要使用Comparator接口 了,因为Comparable接口的compareTo(Object o)方法的实现通常都是基于一个字段(field),无法对其他的属性进行排序。而Comparator接口的compare(Object o1, Object o2)方法接收两个Object类型的参数,因此在实现此方法时可以根据不同的属性进行实现,返回负整数,0,正整数来表示第一个对象小于、等于或大于第 二个对象。

34. Comparable 与 Comparator 接口的区别?

Comparable 和 Comparator 接口都用于对集合或数组内的对象进行排序。Comparable 接口提供了对对象的自然排序(natural sorting)方法,我们也可以基于单一的逻辑(single logic)实现排序方法。
Comparator 接口用于提供普通的排序算法,以至于我们可以选择不同的comparator来对给定的集合进行排序。

35. 如何对list中的对象进行排序?

想 要对数组内的对象进行排序,只需调用Arrays.sort()方法。想要对list中的对象进行排序,只需调用Collections.sort()方 法。但是,这两种方法要么实现了Comparable接口的sort()方法,对集合进行自然排序,要么实现了Comparator接口中的sort() 方法,能按某些条件(criteria)进行排序。其实Collections内部会调用Array的排序方法,因此除了在排序前Collections 类会将list中的元素先复制到数组中消耗点时间外,它们在排序性能上几乎没有差别。

36. 当集合作为参数传入方法中时,如何确保方法不会修改它?

我 们可以通过调用Collections.unmodifiableCollection(Collection c)方法来创建一个只读的集合,然后再将它传入函数中,这样就会确保任何企图修改集合的操作都会引起 UnsupportedOperationException异常。

37. 根据给定的集合如何创建一个synchronized的集合?

可以调用Collections.synchronizedCollection(Collection c)方法,会返回一个同步的集合。

38. Collections框架都实现了哪些常见的算法?

Java Collections 框架提供了常见的像排序和搜索算法的实现。这些方法都在具体的类中进行实现。大多数这些算法都用于操纵List,但有一部分是适用于所有的集合类的。这些 算法有排序,搜索,洗牌(shuffling),极值(min-max values)等。

39. 什么是大O符号(Big-O notation)?请举例?

大O符号用于描述某种算法的性能,这些算法通常被应用于操作包含大量元素的数据结构。由于集合类实际上就是对数据结构的实现,因此大多数情况下,我们都从时间、空间和性能等方面的开销来选择合适的容器,而大O符号就是对这三方面的一种衡量。
例1:ArrayListget(index i)方法的执行时间为常数,并不依赖list的大小,因此用大O符号表示为O(1)。
例2:对数组或链表进行查找,其性能都是O(n),因为我们需要遍历整个集合才能找到元素。

40. Java集合框架都有哪些最佳实践?

  • 要根据需求来选择正确的容器类型,例如,如果大小固定,也许选择Array就比ArrayList更明智。如果想按插入顺序对Map进行迭代,那么需要选TreeMap。如果集合不允许重复,那么就应该选Set。
  • 某些集合类允许指定初始容量,如果我们能粗略的估计下要存储元素的数量,那么我们就可能避免重新hash(rehashing)和自动扩容(resizing)所带来的某些性能问题。
  • 要针对接口编程而不是针对实现编程,这允许我们以后可以轻松的变更实现。
  • 要尽可能的使用泛型以保证类型安全,从而避免运行时的ClassCastException异常。
  • 使用JDK提供的不可变的(immutable)类型来作为Map的键,从而避免自己实现hashCode() 和equals()方法。
  • 尽可能多的使用Collections这一工具类,因为我们可以很轻松的调用它已实现的算法或用来获取只读的、同步的或空的集合对象,从而避免自己实现。这会极大的提高代码的复用性、稳定性,降低维护成本。

41. Java集合类的属性

20170306015717556.jpg-72.6kB20170306015717556.jpg-72.6kB

参考资料

相关文章

  • Java集合框架面试题

    标签(空格分隔): Java集合框架 面试题汇总 1. 什么是Java集合框架?请列举出集合(Collection...

  • 集合相关

    Java面试题 1.Java集合框架是什么?说出一些集合框架的优点? 集合框架的部分优点如下: 使用核心集合框类降...

  • Java 集合框架_开篇

    Java 集合框架系列 Java 集合框架_开篇Java 集合框架_ListJava 集合框架_ArrayList...

  • Java 集合框架_List

    Java 集合框架系列 Java 集合框架_开篇Java 集合框架_ListJava 集合框架_ArrayList...

  • 华为2019年最新java面试题疑似泄露?!

    华为2019年java最新面试题泄露?!不管真实性如何,这些题目还是进大厂必备! Java 集合类以及集合框架;H...

  • 【集合框架】

    集合框架(怎么实现、适用场景) hash相关 Java集合框架 Java集合框架综述Java集合框架面试问题集锦 ...

  • 面试必备——Java集合框架

    Java集合框架面试题 常见集合 集合可以看作是一种容器,用来存储对象信息。数组和集合的区别:(1)数组长度不可变...

  • Java基础面试总结

    【面试汇总】Java面试题-1Java面试题-2 【集合】Java集合及concurrent并发包总结(转)Jav...

  • Spring“集合”注入、Spring AOP实现(2)

    一、Java集合框架 1、集合框架 Java Collections Framework2.png 各种集合框架的...

  • Java面试题及答案整理(图文)

    Java面试题集涵盖了java所有的知识点,及java项目开发中涉及到的各种框架 。包含了 Java 集合、JVM...

网友评论

  • tinycoder:40条第一点,“如果想按插入顺序对Map进行迭代,那么需要选TreeMap”,应该是LinkedHashMap
  • 思而忧:写得很好,能让人更好理解Collectioin集合框架了。

本文标题:Java集合框架面试题

本文链接:https://www.haomeiwen.com/subject/snpnottx.html