java collectionJava学习笔记collection

Java集合框架面试题

2017-04-03  本文已影响1982人  outSiderYN

标签(空格分隔): 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

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

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

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

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有何不同?

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,然而在使用前请仔细考虑以下方面:

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

21. HashMap与Hashtable有何区别?

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

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

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

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

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

25. 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集合框架都有哪些最佳实践?

41. Java集合类的属性

20170306015717556.jpg-72.6kB20170306015717556.jpg-72.6kB

参考资料

上一篇下一篇

猜你喜欢

热点阅读