面试系列-集合框架

集合框架

1、ArrayList和Vector的区别

  这两个类都实现了List接口(List接口继承了Collection接口),他们都是有序集合,即存储在这两个集合中的元素的位置都是有顺序的,相当于一种动态的数组,我们以后可以按照位置索引取出某个元素,并且其中的数据是允许重复的,这是HashSet之类的集合的最大不同之处,HashSet之类的集合不可以按照索引号去检索其中的元素,也不允许有重复的元素。
  ArrayList和Vector的区别

  • 同步性
      Vector是线程安全的,也就是说它的方法之间是线程同步的,而ArrayList是线程不安全的,它的方法之间的线程不同步的。如果只有一个线程会访问到该集合,那么最好使用ArrayList,因为它不考虑线程安全,效率会高一点。如果需要多个线程进行访问,那么就需要使用Vector,因为不需要我们自己再去考虑和编写线程安全相关的代码内容。

  备注:对于Vector和ArrayList、Hashtable和HashMap,要记住线程安全的问题。记住Vector 于 HashTable 是旧的,是Java一诞生就提供了,它们是线程安全的,ArrayList 于HashMap 是Java2 的时候才提供的,它们是线程不安全的。

  • 数据增长

  ArrayList与Vector都有一个初始的容量大小,当存储进它里面的元素个数超过了容量的时候,就需要增加ArrayList与Vector的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间需要取得一个平衡。Vector默认增长为原来的两倍,而ArrayList的增长策略在文档中没有明确的说明(从源码的角度上来看是增长到原来的1.5倍)。ArrayList与Vector都可以设置初始的空间大小,Vector还可以设置增长的空间大小,而ArrayList没有提供设置增长空间的方法。

  总结:即Vector增长原来的一倍,ArrayList增加原来的0.5倍

2、说说ArrayList,Vector,LinkedList的存储性能和特性

  ArrayList 和Vector 都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized 方法(也就是线程安全的)
  通常性能上的比较ArrayList 的性能较差,而LinkedList 使用双向链表实现存储,按序号索引数据需要进行向前或者向后的遍历,但是插入数据的时候只需要记录本项的前后数据即可,所以插入数据较快。
  ArrayList在查找的时候速度快,LinkedList在插入删除的时候速度快。

3、快速失败(fail-fast) 和安全失败(fail-safe) 的区别是什么?

  Iterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响。java.util包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面的所有类都是安全失败的。快速失败的迭代器会抛出ConcurrentModificationException异常,而安全失败的迭代器永远不会抛出这样异常。

4、HashMap的数据结构

  在Java 编程语言中,最基本的结构就是两种,一种是数组,一种是模拟指针,所有的数据结构都可以使用这两种基本的结构来构造,HashMap也不例外,实际上HashMap是使用数组和链表的结合体,在Java8之后将链表数据结构进行了优化。
在这里插入图片描述

5、HashMap的工作原理是什么?

  Java中的HashMap是以键值对的形式存储元素,HashMap需要是一个hash函数,它使用hashCode()和equal()方法来向集合中增加元素,或者是从集合中查找元素。当调用put()方法的时候,HashMap会计算key的Hash值,然后把键值对存储到集合中合适的索引上,如果key已经存在,value的值就会被更新为新的值,HashMap的一些重要的特性是它的容量操作和负载因子,扩容极限等内容

6、HashMap什么时候进行扩容

  当HashMap 中的元素个数超过数组大小loadFactor的时候就会进行数组扩容,loadFactor的默认值是0.75,也就是说,在默认情况下,数组大小为16,那么当HashMap中元素个数超过12的时候,就把数组的大小扩展为32,也就是16的两倍。然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以说如果没有已经预知HashMap中元素的个数,那么预设元素的个数能够有效的提高HashMap的性能,例如说,我们有1000个元素new HashMap(1000),但从理论上来讲 new HashMap(1024)更为合适,根据上面所说的即使是1000,HashMap也会自动将其设置为1024,但是new HashMap(1024) 还不是更合适,因为750<1000,也就是说需要让0.75*size>1000,所以说设置为2048更为合适,这个也就是需要考虑到resize()非常耗时的问题。

7、List、Map、Set 三个接口,存取元素的时候,各有什么特点?

  首先List与Set具有相似性,它们都是单列表元素的集合,所以,它们有一个公共的父类叫做Collection。Set里面不允许有重复的元素,所谓的重复,既不能有两个相等对象,即假设Set集合中有一个对象A,现在要想Set集合中再存入一个B对象,但是B对象与A对象equals相等,则B对象存储不进去,所以,Set集合的add方法有一个boolean的返回值,当集合中没有某个元素的时候,测试add方法可成功加入该元素时,则返回true,当集合中含有某个元素equals相等的元素时,此时add方法无法加入该元素,返回结果为false。Set取元素时,没法说取第几个,只能以Iterator接口取得所有的元素,再逐一进行遍历各个元素

  List 表示 有先后顺序的集合,注意,这里不是按照年龄、按照大小、按照大小之类的排序。当我们多次调用add(Object) 方法的时候,每次加入的对象就像是火车站排队买票一样,按照先后顺序进行排序,有的时候也可以插队,也就是调用add(index,Object)方法,就可以在指定的位置加入对象了,一个对象可以被反复存储进入List中,每次调用add方法,这个对象就被加入进集合一次,其实,并不是是把这个对象本身存储到集合中,而是在集合中有一个索引变量指向这个对象,当这个对象被add多次的时候,相当于集合中多个索引指向了这个对象。

  Map 与List 和Set 不同,它是双列的集合,其中的put方法,定义如下

  • put(obj key,obj value);每次存储的时候,需要存储一对kv,不能存储重复的key,这个重复的规则也是按照equals比较。获取的时候可以根据对应的key获取到对应的value,也就是调用get(Object key) 返回key对应的value,另外也可以获取到所有key的集合,还可以获取到所有value的集合,还可以获取到所有KV的集合的对象Map.Entry对象集合。

  List以特定的次序来持有元素,可以有重复元素。Set无法拥有重复元素,内部排序。Map保存kv值,value可以多值

8、Set里的元素时不能重复的,那么用什么方法来区分重复与否?是用==还是用equals()?它们有何区别?

  Set里的元素是不能重复的,元素重复与否是使用equals()方法进行判断的。

  equals()和== 方法决定引用值是否指向同一对象equals()在类中被覆盖,为的是当两个分离的对象的内容和类型想匹配的时候,返回真值。

9、两个对象值相同(x.equals(y)==true),但是却可以有不同的hashcode,是否正确?

  对,如果对象要保存在HashSet 或者是HashMap中,它们的equals相等,那么它们的hashcode值就必须相等。
  如果不是要保存在HashSet或者HashMap,则与hashcode没有关系了,这个时候hashcode不等是可以的,例如ArrayList存储的对象就不用事先hashcode,当然,我们没有理由不实现,通常都是去实现的。

10、heap和stack 有什么区别

  Java的内存分为两类,一是栈内存,一是堆内存。栈内存是指程序进入一个方法时,会为这个方法单独分配一块私有空间,对于存储这个方法内部的局部变量,这个方法结束时,分配这个方法的栈会释放,这个栈中的变量随之释放。
  堆是与栈作用不同的内存,一般用于存放不放在当前方法栈中的那些数据,例如,使用new创建的对象都放在堆内存中,所以,它不会随方法的结束而消失。而方法中的局部变量使用final修饰之后放在堆中,而不是栈中。

11、Java集合类框架的基本接口有哪些?

  集合类接口指定了一组叫做元素的对象。集合类接口的每一种具体的实现类都可以选择它自己的方式对元素进行保存和排序。有的集合类允许重复键,有些不允许。Java集合类提供了一套设计良好的支持对一组对象进行操作的接口和类。Java集合类中的基本接口如下

  • Collection:代表一组对象,每一个对象都是它的子元素
  • Set:不包含重复元素的Collection
  • List:有顺序的Collection,并且可以包含重复元素
  • Map:可以把键(Key)映射到值(Value)的对象,键不能重复

12、HashSet和TreeSet的区别

  HashSet是由一个Hash表来实现的,因此他的元素时无序的,add(),remove(),contains()。
  TreeSet是由一个树形结构来实现的,它里面的元素是有序的,因此,add(),remove(),contains() 方法的时间复杂度是O(logn)

13、HashSet底层实现是什么?

  通过查看源码可以知道HashSet的实现是依赖于HashMap的,HashSet的值都是存储在HashMap中的。在HashSet的构造方法中会初始化一个HashMap的对象,HashSet不允许重复,因此,HashSet的值作为HashMap的key存储在HashMap中,当存储的值已经存在的时候返回false

14、LinkedHashMap的实现原理?

  LinkedHashMap也是基于HashMap实现的,不同的是它定义了一个Entry header,这个header不是放在Table里面,它是额外独立出来的。
  LinkedHashMap通过继承HashMap中的Entry,并添加两个属性Entry before ,after和header 结合起来形成一个双向链表,来实现安插顺序或访问顺序排序。LinkedHashMap定义了排序模式AccessOrder,该属性为Boolean型变量,对于访问顺序,为true;对于插入顺序为false,一般情况下,不必指定排序模式,其迭代顺序即为默认为插入顺序。

15、为什么集合类没有实现Cloneable和Serializable接口?

  克隆(cloning)或者是序列化(Serializable)的语义和含义是跟具体的实现相关的,因此,应该由集合类的具体实现来决定如何被克隆或者被序列化。

16、什么是迭代器(Iterator)?

  Iterator 接口提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返回迭代器实例的迭代方法。迭代器可以在迭代的过程中删除底层集合的元素,但是不可以直接调用集合的remove(Object obj)删除,可以通过迭代器的remove()方法删除。

17、Iterator和ListIterator的区别是什么?

Iterator 用来遍历Set和List集合,但是ListIterator只能用来遍历List;
Iterator 对集合只能是前向遍历,ListIterator既可以前向也可以后向;
ListIterator 实现了Iterator接口,并包含其他的功能,例如:增加元素,替换元素,获取前一个和后一个元素的索引,等等

18、数组(Array)和列表(ArrayList) 有什么区别?什么时候应该使用Array而不是ArrayList?

  • Array 可以包含基本类型和对象类型,ArrayList只能包含对象类型
  • Array 大小是固定的,ArrayList的大小是动态变化的
  • ArrayList 处理固定大小的基本数据类型时候,这种方式相对比较慢

19、Java集合类框架是最佳实践有哪些?

  • 假如元素的大小是固定的,而且事先知道,我们就应该用Array而不是ArrayList。
  • 有些集合类允许指定初始容量。因此,如果我们能估计出存储的元素的数目,我们可以设置初始容量来避免重新计算hash值或者是扩容
  • 为了类型安全,可读性和健壮性的原因总是要使用泛型,同时,使用泛型还可以避免运行时ClassCastException。
  • 使用JDK提供的不变类作为Map的键可以避免为我们自己的类实现hashCode和equals方法
  • 编程的时候接口由于实现
  • 底层的集合实际上是空的情况下,返回长度是0是集合或者是数组,不要返回null。

20、Set里的元素是不能重复的,那么用什么方法来区分重复与否呢?是用==还是equals()?它们有何区别?

  Set 里的元素是不能重复的,那么用Iterator()方法来区分重复与否。equals() 是判断两个Set是否相等

  equals() 和 == 方法决定引用值是否指向同一对象 equals()在类中被覆盖,为的是当两个分离的对象的内容和类型相匹配的时候,返回真值。这个之前提到过

21、Comparable 和Comparator 接口是干什么的》列出它们的区别。

  Java提供了只包含一个compareTo()方法的Comparable 接口。这个方法可以给两个对象排序,具体说,它返回负数,0 ,正数 来表明输入对象小于,等于,大于已经存在的对象。

  Java提供了包含compare() 和equals() 两个方法的Comparator接口。compare()方法用来给两个输入参数排序,返回负数,0,正数表明第一个参数是小于,等于,大于第二参数。equals()方法需要一个对象作为参数,它用来决定输入参数是否和comparator相等。只有当输入参数也是一个comparator并且输入参数和当前comparator的排序结果是相同的时候,这个方法才返回true。

22 、Collection 和Collections的区别

  • collection 是集合类的上级接口,继承与它的接口主要是Set和List
  • Collections 是针对集合类的一个帮助类,它提供一系列的静态方法对各种集合的搜索,排序,线程安全化等操作。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nihui123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值