集合相关面试题
集合相关面试题
1. Collection和Collections的差别
java.util.Collection 是一个集合接口,Collection接口在Java类库中有非常多详细的实现。比如List、Set
java.util.Collections 是针对集合类的一个帮助类,它提供了一系列的静态方法实现对各种集合的搜索、排序、线程安全化等操作。
2. ArrayList与Vector的差别
这两个类都实现了List接口(List接口继承自Collection接口)。它们都是有序集合。它们内部的元素都是能够反复的,都能够依据序号取出当中的某一元素。
它们两个的差别在于:
(1)、线程安全的问题:Vector是早期Java就有的,是线程安全的;而ArrayList是在Java2中才出现,它是线程不安全的,仅仅能使用单线程操作。 因为Vector支持多线程操作,所以在性能上就比不上ArrayList了。
相同的HashTable相比于HashMap也是支持多线程的操作而导致性能不如HashMap。
(2)、数据增长的问题
ArrayList和Vector都有一个初始的容量大小,当存储进去它们里面的元素个数超出容量的时候。就须要添加ArrayList和Vector的存储空间,每次添加存储空间的时候不是仅仅添加一个存储单元。是添加多个存储单元。
Vector默认添加原来的一倍,ArrayList默认添加原来的0.5倍。
Vector能够由我们自己来设置增长的大小,ArrayList没有提供相关的方法。
3. Array和ArrayList有何区别?什么时候更适合用Array?
Array可以容纳基本类型和对象,而ArrayList只能容纳对象。
Array是指定大小的,而ArrayList大小是固定的。
Array没有提供ArrayList那么多功能,比如addAll、removeAll和iterator等。尽管ArrayList明显是更好的选择,但也有些时候Array比较好用。
(1)如果列表的大小已经指定,大部分情况下是存储和遍历它们。
(2)对于遍历基本数据类型,尽管Collections使用自动装箱来减轻编码任务,在指定大小的基本类型的列表上工作也会变得很慢。
(3)如果你要使用多维数组,使用[][]比List<List<>>更容易。
4. LinkedList与ArrayList有什么差别
两者都实现的是List接口。不同之处在于:
(1)、ArrayList是基于动态数组实现的,LinkedList是基于链表的数据结构。
(2)、get訪问List内部随意元素时,ArrayList的性能要比LinkedList性能好。LinkedList中的get方法是要依照顺序从列表的一端開始检查,直到另一端
(3)、对于新增和删除操作LinkedList要强于ArrayList。由于ArrayList要移动数据
5. HashMap与HashTable的差别
两者都实现了Map接口。主要差别在于:
(1)、HashTable是早期Java就有的,支持多线程操作。是线程安全的。HashMap是Java2才出现的。是HashTable的轻量级实现,仅支持单线程操作。线程不安全的。
(2)、HashMap允许空的key和value,HashTable不同意
6. List与Map的差别
List是存储单列数据的集合,Map是存储key和value这样双列数据的集合,List中存储的数据是有顺序的,而且允许相同的值。
Map其中存储的数据是没有顺序的,它存储的key是不能反复的,value是能够反复的。
List继承Collection接口,Map不是。Map没有父类
7. List、Map、Set三个接口。存取元素时各有什么特点
首先List和Set都是单列元素的集合。它们有一个共同的父接口Collection。
List内的元素讲究有序性。内部元素可相同。可是Set恰恰相反。它讲究的是无序性,元素不可相同。Set的add方法有一个boolean的返回值,每当add一个新元素的时候都会调用equals方法进行逐一比較,当新元素与全部的已存在元素的都不相同的时候add成功返回true。否则返回false。
Map与List和Set不同,它是双列存储的(键和值一一对应)。它在存储元素调用的是put方法,每次存储时,要存储一份key和value。不能存储相同的key,这个相同的规则也是利用equals进行比較。取数据的时候则能够依据key获取value。另外还是以获得全部key的集合和全部value的集合。还能够获得key和value组成的Map.Entry对象的集合。
8. 介绍一下TreeSet
Java中的TreeSet是Set的一个子类,TreeSet集合是用来对象元素进行排序的,同样他也可以保证元素的唯一。
9. 哪些集合类提供对元素的随机访问?
ArrayList、HashMap、TreeMap和HashTable类提供对元素的随机访问。
10. EnumSet是什么?
java.util.EnumSet是使用枚举类型的集合实现。当集合创建时,枚举集合中的所有元素必须来自单个指定的枚举类型,可以是显示的或隐示的。EnumSet是不同步的,不允许值为null的元素。它也提供了一些有用的方法,比如copyOf(Collection c)、of(E first,E…rest)和complementOf(EnumSet s)。
11. 哪些集合类是线程安全的?
Vector、HashTable、Properties和Stack是同步类,所以它们是线程安全的,可以在多线程环境下使用。Java1.5并发API包括一些集合类,允许迭代时修改,因为它们都工作在集合的克隆上,所以它们在多线程环境中是安全的。
12. 并发集合类是什么?
Java1.5并发包(java.util.concurrent)包含线程安全集合类,允许在迭代时修改集合。迭代器被设计为fail-fast的,会抛出ConcurrentModificationException。一部分类为:CopyOnWriteArrayList、 ConcurrentHashMap、CopyOnWriteArraySet。
13. BlockingQueue是什么?
Java.util.concurrent.BlockingQueue是一个队列,在进行检索或移除一个元素的时候,它会等待队列变为非空;当在添加一个元素时,它会等待队列中的可用空间。BlockingQueue接口是Java集合框架的一部分,主要用于实现生产者-消费者模式。我们不需要担心等待生产者有可用的空间,或消费者有可用的对象,因为它都在BlockingQueue的实现类中被处理了。Java提供了集中BlockingQueue的实现,比如ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue,、SynchronousQueue等。
14. 队列和栈是什么,列出它们的区别?
栈和队列两者都被用来预存储数据。java.util.Queue是一个接口,它的实现类在Java并发包中。队列允许先进先出(FIFO)检索元素,但并非总是这样。Deque接口允许从两端检索元素。
栈与队列很相似,但它允许对元素进行后进先出(LIFO)进行检索。
Stack是一个扩展自Vector的类,而Queue是一个接口。
15. Comparable和Comparator接口是什么?
如果我们想使用Array或Collection的排序方法时,需要在自定义类里实现Java提供Comparable接口。Comparable接口有compareTo(T OBJ)方法,它被排序方法所使用。我们应该重写这个方法,如果“this”对象比传递的对象参数更小、相等或更大时,它返回一个负整数、0或正整数。但是,在大多数实际情况下,我们想根据不同参数进行排序。比如,作为一个CEO,我想对雇员基于薪资进行排序,一个HR想基于年龄对他们进行排序。这就是我们需要使用Comparator接口的情景,因为Comparable.compareTo(Object o)方法实现只能基于一个字段进行排序,我们不能根据对象排序的需要选择字段。Comparator接口的compare(Object o1, Object o2)方法的实现需要传递两个对象参数,若第一个参数比第二个小,返回负整数;若第一个等于第二个,返回0;若第一个比第二个大,返回正整数。
16. Comparable和Comparator接口有何区别?
Comparable和Comparator接口被用来对对象集合或者数组进行排序。Comparable接口被用来提供对象的自然排序,我们可以使用它来提供基于单个逻辑的排序。
Comparator接口被用来提供不同的排序算法,我们可以选择需要使用的Comparator来对给定的对象集合进行排序。
17. 我们如何对一组对象进行排序?
如果我们需要对一个对象数组进行排序,我们可以使用Arrays.sort()方法。如果我们需要排序一个对象列表,我们可以使用Collection.sort()方法。两个类都有用于自然排序(使用Comparable)或基于标准的排序(使用Comparator)的重载方法sort()。Collections内部使用数组排序方法,所有它们两者都有相同的性能,只是Collections需要花时间将列表转换为数组。
18. 如何决定选用HashMap还是TreeMap?
对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择。然而,假如你需要对一个有序的key集合进行遍历,TreeMap是更好的选择。基于你的collection的大小,也许向HashMap中添加元素会更快,将map换为TreeMap进行有序key的遍历。
HashMap:数组方式存储key/value,线程非安全,允许null作为key和value,key不可以重复,value允许重复,不保证元素迭代顺序是按照插入时的顺序,key的hash值是先计算key的hashcode值,然后再进行计算,每次容量扩容会重新计算所以key的hash值,会消耗资源,要求key必须重写equals和hashcode方法
默认初始容量16,加载因子0.75,扩容为旧容量乘2,查找元素快,如果key一样则比较value,如果value不一样,则按照链表结构存储value,就是一个key后面有多个value;
TreeMap:基于红黑二叉树的NavigableMap的实现,线程非安全,不允许null,key不可以重复,value允许重复,存入TreeMap的元素应当实现Comparable接口或者实现Comparator接口,会按照排序后的顺序迭代元素,两个相比较的key不得抛出classCastException。主要用于存入元素的时候对元素进行自动排序,迭代输出的时候就按排序顺序输出
19. 在Java中,HashMap是如何工作的?
HashMap在Map.Entry静态内部类实现中存储key-value对。HashMap使用哈希算法,在put和get方法中,它使用hashCode()和equals()方法。当我们通过传递key-value对调用put方法的时候,HashMap使用Key hashCode()和哈希算法来找出存储key-value对的索引。Entry存储在LinkedList中,所以如果存在entry,它使用equals()方法来检查传递的key是否已经存在,如果存在,它会覆盖value,如果不存在,它会创建一个新的entry然后保存。当我们通过传递key调用get方法时,它再次使用hashCode()来找到数组中的索引,然后使用equals()方法找出正确的Entry,然后返回它的值。下面的图片解释了详细内容。
其它关于HashMap比较重要的问题是容量、负荷系数和阀值调整。HashMap默认的初始容量是32,负荷系数是0.75。阀值是为负荷系数乘以容量,无论何时我们尝试添加一个entry,如果map的大小比阀值大的时候,HashMap会对map的内容进行重新哈希,且使用更大的容量。容量总是2的幂,所以如果你知道你需要存储大量的key-value对,比如缓存从数据库里面拉取的数据,使用正确的容量和负荷系数对HashMap进行初始化是个不错的做法。
面试过程(大家看看下面的几个问题是否可以回答上来):
HashMap是否有序?
有没有有顺序的Map实现类?
TreeMap和LinkedHashMap是如何保证它的顺序的?
查看原文:http://www.coder306.cn/?p=125