java中有关集合(容器)的问题整理

整理了下有关Java集合有关的面试问题


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

每种编程语言中都有集合,最初的Java版本包含几种集合类:Vector、Stack、HashTable和Array。随着集合的广泛使用,Java1.2提出了囊括所有集合接口、实现和算法的集合框架。在保证线程安全的情况下使用泛型和并发集合类,Java已近经历了很久。它还包括在Java并发包中,阻塞接口以及他们的实现。
集合框架的部分优点如下:

  • 1.使用核心集合类降低开发成本,而非实现我们自己的集合类
  • 2.随着使用经过严格测试的集合框架类,代码质量会得到提高
  • 3.通过使用JDK附带的集合类,可以降低代码维护的成本。
  • 4.复用性和可操作性
2.集合框架中的泛型有什么优点?

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

3.Java集合框架的基础接口有哪些

Collection为集合层级的根接口。一个集合代表一组对象,这
些对象即为它的元素。Java平台不提供这个接口任何直接的实现。 Set是一个不能包含重复元素的集合。这个接口对数学集合抽象进行建模,被用来代表集合,就如一副牌。 List是一个有序集合,可以包含重复元素。你可以通过它的索引来访问任何元素。List更像长度动态变换的数组。Map是一个将key映射到value的对象.一个Map不能包含重复的key:每个key最多只能映射一个value。 一些其它的接口有Queue、Dequeue、SortedSet、SortedMap和ListIterator。

4.为何Map接口不继承Collection接口?

尽管Map接口和它的实现也是集合框架的一部分,但是Map不是集合,集合也不是Map。因此,Map继承Collection毫无意义,反之亦然。如果Map继承Collection接口,那么元素去哪儿?Map包含Key-Value对,它提供抽取Key或value列表集合的方法,但是它不适合“一组对象”规范。

5.Enumeration和Iterator接口的区别?

Enumeration的速度是Iterator的两倍,也使用更少的内存。Enumeration是非常基础的,也满足了基础的需要。但是,与Enumeration相比,Iterator更加安全,因为当一个集合正在被遍历的时候,它会阻止其它线程去修改集合。 迭代器取代了Java集合框架中的Enumeration。迭代器允许调用者从集合中移除元素,而Enumeration不能做到。为了使它的功能更加清晰,迭代器方法名已经经过改善。

6.HashMap与HashTable有何不同?

1.HashMap允许key和value为空,而HashTable不允许
2.HashTable是同步的,而HashMap不是。所以HashMap适合单线程环境,HashTable适合多线程环境
3.在Java1.4中引入了LinkedHashmap,HashMap的一个子类,假如你想要遍历序列,你很容易从HashMap转向LinkedHashMap,但是HashTable不是这样,它的顺序是不可预知的。
4.HashMap提供对Key的Set进行遍历,因此他是fail-fast的,但HashTable提供对Key的Enumeration进行遍历,它不支持fail-fast
5.HashTable被认为是一个遗留的类,如果你寻求在迭代的时候修改Map,你应该使用ConcurrentHashMap。

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

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

8.ArrayList和Vector有何异同点?

相同点

  • 1.两者都是基于索引的,内部由一个数组支持。
  • 2.两者维护插入的顺序,我们可以根据插入顺序来获取元素
  • 3.ArrayList和Vector的迭代器的实现都是fail-fast的
  • 4.ArrayList和Vector两者都允许NULL值,也可以使用索引值对元素进行随机访问。

不同点

  • 1.Vector是同步的,而ArrayList不是。然而,如果你寻求在迭代的时候对列表进行改变,你应该使用CopyOnWriteArrayList。
  • 2.ArrayList比Vector快,Vector因为有同步,不会过载。
  • 3.ArrayList更加通用,因为我们可以使用Collections工具类轻易的获取同步列表和只读列表。
9.Array和ArrayList有什么区别?什么时候更适合用Array?

Array可以容纳基本类型和对象,而ArrayList只能容纳对象。Array是指定大小的,而ArrayList大小是固定的。Array没有提供ArrayList那么多功能,比如addAll、removeAll和iterator等。尽管ArrayList明显是更好的选择,但也有时候Array比较好用。

10.Arraylis和LinkedList有什么区别?
  • 1.ArrayList是由Array所支持的基于一个索引的数据结构,所以它提供对元素的随机访问,复杂度为O(1),但LinkedList存储一系列的节点数据,每个节点都与前一个和下一个节点相连。所以,尽管有使用索引获取元素的方法,内部实现是从起始点开始遍历,遍历到索引的节点然后返回元素,时间复杂度为O(n),比ArrayList要慢。
  • 2.与ArrayList相比,在LinkedList中插入、添加和删除一个元素会更快,因为在一个元素插入到中间的时候,不会涉及改变数组的大小,或者跟新索引。
  • 3.LinkedList比ArrayList消耗跟多的内存,因为LinkedList中的每个节点存储了前后节点的引用
11.那些集合类提供对元素的随机访问?

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

12.那些集合类是线程安全的

Vector,Hashtable,Properties和Stack是同步类,所以他们是线程安全的,可以在多线程环境下使用。Java1.5并发API包括一些集合类,允许迭代时修改,因为他们都工作在集合的克隆上,所以他们在多线程环境中是安全的。

13.并发集合类是什么?

Java1.5并发包(java.util.concurrent)包含线程安全集合类,允许在迭代时修改集合。迭代器被设计为fail-fast的,会抛出ConcurrentModificationException。一部分类为:CopyOnWriteArrayList,ConcurrentHashMap,CopyOnWriteArraySet。

14.谈谈常用的集合?

在这里插入图片描述
Java容器分为Collection和Map两大类,Collection集合的子接口有Set,List,Queue三种。我们比较常用的是Set,List,Map接口不是Collection的子接口。


Collection集合主要有List和Set两大接口

  • List:一个有序(元素存入集合的顺序和取出的顺序一致)容器,元素可以重复,可以插入多个null元素,元素都有索引。常用的实现类有ArrayList,LinkedList和Vector
  • Set:一个无序(存入顺序和取出顺序可能不一致)容器,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。Set接口常用实现类是HashSet。LinkedHashSet以及TreeSet。

Map是一个键值对集合,存储键,值之间的映射。Key无序,唯一;Value不要求有序,允许重复。Map没有继承与Collection接口,从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。
Map的常用实现类:HashMap,TreeMap,HashTable,LinkedHashMap,ConcurrentHashMap


集合框架底层数据结构

Collection

  • 1.list
    • ArrayList:Object数组
    • Vector:Object数组
    • LinkedList:双向循环链表
  • 2.Set
    • HashSet(无序,唯一):基于HashMap实现的,底层采用HashMap来保存元素
    • LinkedHashSet:LinkedHashSet继承于HashSet,并且其内部是通过LinkedHashMap来实现的。有点类似于我们所说的LinkedHashMap其内部是基于HashMap实现一样,不过还是有一点点区别的
    • TreeSet(有序,唯一):红黑树(自平衡的排序二叉树)

Map

  • HashMap:JDK1.8之前HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的("拉链法"解决冲突)。JDK1.8之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间,

更详细的解释可以看这篇文章

  • LinkedHashMap:LinkedHashMap继承自HashMap,所以它底层仍然是基于拉链式散列结构,即由数组和链表或红黑树组成。另外,LinkedHashMap在上面结构的基础上,增加了一条双向链表,是个上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑
  • HashTable:数组+链表组成,数组是HashTable的主体,链表则主要为了解决哈希冲突而存在的
  • TreeMap:红黑树(自平衡的排序二叉树)
15.ArrayList的扩容机制

ArrayLis是List接口的实现类,他是根据需要而动态增长的数组。java中标准数组是定长的,在数组被创建之后,他们不能被加长或者缩短。这就意味着在创建数组时需要知道数组的所需长度,但我们需要在动态程序中获取数组长度。ArrayList就是为此而生的,但是他不是线程安全的,此外ArrayList按照插入的顺序来存放数据。

  • 1.ArrayList扩容发生在add()方法调用的时候,调用ensureCapacityInternal()来扩容的。通过方法calculateCapacity(elementData,minCapacity)获取扩容的长度
  • 2.ensureExplicitCapacity方法可以判断是否需要扩容
  • 3.ArrayList扩容的关键方法grow():获取到ArrayList中elementData数组的内存空间长度,扩容至原来的1.5倍
  • 4.调用Arrays.copyOf方法将elementData数组指向新的内存空间时newCapacity的连续空间,从此方法中我们可以清晰的看出其实ArrayList扩容的本质就是计算出新的扩容数组的size后实例化,并将原有数组内容复制到新数组中去。
16.Java中HashMap如何解决哈希碰撞的

首先明确,Map是entry的集合,一个key,Value,就是一个entry
在这里插入图片描述
Java在处理Hash冲突的时候使用了链表

图中的0到10 号的方块就是entry(键值对),如果发生了hashcode的冲突,就会像4号方块那样,开始向后追加,注意看4号方块的next属性,那个属性不是null,而是指向了一个方块。

17.ConcurrentHashMap如何实现并发访问的?

ConcurrentHashMap是Java5中新增加的一个线程安全的Map集合,可以用来替代HashTable。HashTable容器在竞争激烈的并发环境下表现出效率低下的原因是所有访问HashTable的线程都必须竞争同一把锁,那假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问

ConcurrentHashMap的结构

ConcurrentHashMap类中包含两个静态内部类HashEntry和Segment。HashEntry用来封装映射表的键/值对;Segment用来充当锁的角色,每个Segment对象守护整个散列映射表的若干个桶。每个桶是由若干个HashEntry对象链接起来的链表。一个ConcurrentHashMap实例中包含由若干个Segment对象组成的数组。CurrentHashMap的类图如下所示:
在这里插入图片描述
ConcurrentHashMap的内部结构:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值