Java集合框架面试题

Collection体系集合

请添加图片描述

1.ArrayList和Vector的区别。

这两个类都是List接口下的实现类,而List下总共有三个实现类,分别是ArrayList、LinkedList、Vector。List用于存放多个元素,其中的元素是由于可重复的。

  • ArrayList是List中最常用的实现类,内部是由数组实现的,而数组的缺点是每个元素之间不能有间隔,当数组的存储空间不足时就需要扩容,数组扩时就需要将元素组中的数据复制到新的存储空间中。当ArrayList中需要插入或删除元素时需要将原数组进行复制、移动的操作代价比较高。因此ArrayList适合于查找和遍历,不适合于插入和删除操作.
  • vector与ArrayList相同的时他们的底层都是由数组实现的,不同的是vector是线程同步的,就是某一时间内只能有一个线程对vector进行操作。这样就可以避免多线程操作vector导致的数据不一致。但是会降低效率。
  • LinkedList底层是由链表结构存储数据的。适合于插入和删除操作。但是不适合于查询和遍历操作。

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

ArrarListvector的底层都是由数组实现的其存储时必须存储在一片连续的空间上,数组的优势在于其查询的速度快,但是当数组的存储空间不足时就涉及到数组的扩容,数组扩容需要将原有的数据复制到新的存储空间中。插入和删除的操作需要对数组进行复制和移动的操作代价较高。vectorArrayList的区别在于Vector时线程安全的。

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

  • 快速失败 Iterator在遍历一个集合对象的时候,如果集合对象进行了修改(增、删、改)操作那么皆会抛出Concurrent Modification Exception异常;
    • 原理:Iterator在遍历的过程中会有一个modcount的变量,集合在修改操作的过程中就会修改modcount的值,在集合进行遍历的时候会有一个expectedmodCount的值当在迭代的过程中如果发现modeCount的值和expectedmodCount的值不相同的时候就会抛出Concurrent Modification Exception异常
    • 注意:java.util包下的集合类都是快速失败的。不能在多线程并发下修改
  • 安全失败采用安全失败的集合不是在原集合内容上进行操作的,而是先拷贝原集合,在拷贝的集合上进行操作的。
    • 原理:在拷贝的集合上进行操作就不会导致modCountexceptedModCount的值不同,因此不会触发Concurrent Modification Exception
    • 缺点:安全失败避免了Concurrent Modification Exception异常,但是迭代器是在拷贝的集合上进行操作的,所以迭代其实无法发访问到修改后的内容。即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的
    • 注意:java.util.concurrent包下的集合都是安全失败的。可以在多线程并发下进行修改操作

4.hashmap 的数据结构。

hashmap的数据结构为:数组+链表+红黑树(jdk1.8添加的)

hasnmap进行存储值时会先会根据key值的hash%数组的长度值计算出key值在数组中存储位置的下标,将其value值封装成一个包含hash值,key值,value值和next的实体存储在对应的数组位置后的链表中。当同一链表上的长度过长时(长度大于8时)链表就会转换为红黑树,以提高查找的效率。

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

hashmap是map的一个实现类,故其是以key-value进行存储的,但是hashmap的底层是由数组+链表+红黑树实现存储的。存储时会先根据key值的hash值进行对数组长度取余运算,计算出其在hash表中的存储位置,再将其key-value和下一个节点封装起来存储到链表中。当链表的长度大于8的时候就会将链表转换为红黑树以提高其查询效率。

6.Hashmap什么时候进行扩容呢?

hashmap的扩容发生在其数组中存储的数据=数组的长度*loadFactor(上座率)时。loadFactor的默认值为0.75。hashmap扩容一次扩容为原来的两倍。因为其扩容的时候所有的元素的hash值对数组长度取余后都可能会不同,所以所有的元素都要重新计算存储位置进行存储。这一过程对程序来说是非常漫长的,所以我们在使用hashmap的时候尽量在创建之初就计算好我们的一个大概的长度(长度要考虑到长度乘以loadFactor)尽量避免在程序运行过程中hashmap扩容这一操作。

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

单独这个问题提问时可以简述其三个接口的底层原理

存值时:

  • List以特定的索引(有顺序的存放)来存放元素,可以有重复的元素
  • map保存键值对的映射,映射关系可以是一对一或多对一,键值是无序的不可重复的,值可以重复
  • set存放的元素是无序的不可重复的

取值时:

  • List可以通过基本for循环,增强for循环以及迭代器iterator来取值
  • map在取值时需要先将其所有的key值拿到转换为set在通过迭代器进行取值
  • set通过迭代器进行取值

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

是通过equals来区分是否相同的,因为如果set集合中有两个元素是同一个类,其内容相同但是指向的地址不同如果该类重写了equals方法则第二次add进去的元素会覆盖掉第一次的元素,

==比较的是两个对象的地址是否相同

equals比较的是两个对想的内容是否相同

9.两个对象值相同(x.equals(y) = = true),但却可有不同的hash code,这句话对不对?

对的,当一个类在重写equals方法的时候没有对hashcode进行重写那么会出现equals结果为true但是hashcode不同的情况

10.heap和stack有什么区别。

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

  • collection接口
    • List接口
      • ArrayList实现类
      • LinkedList实现类
      • Vactor实现类
    • Set接口
      • SortedSet接口
        • TreeSet实现类
      • HashSet实现类
      • EnumSet实现类
    • Queue接口
  • Map接口
    • SortedMap接口
      • TreeMap实现类
    • HashMap实现类

12.HashSet和TreeSet有什么区别?

HashSet元素是无序的,TreeSet实现了SortedSet对元素进行自然排序

Hashset必须要重写hashcode方法,相同的String的hashcode是相同的所有不允许存入相同的String类型,HashSet允许元素为null值,但是只允许一个。

TreeSet是二叉树实现的,Tree中的数据是自动排好序的不允许放入null值

13.HashSet的底层实现是什么?

HashSet的底层是基于Hashmap实现的使用的hashmap的方式存储所有数据的,在hashSet中所有的key全部存在Hsahmap的key值上 value是一个统一的值

14.LinkedHashMap的实现原理?

在世用hashMap的时候可能会与带按插入的顺序来取值,但是HashMap在存储的时候是按照KEY的hash值对数组的长度取余来确定存储位置的,是不具备这一功能的,所有由LinkedHshMap维护的顺序有两种,插入顺序和访问顺序,LinkedHashMap底层是通过双链表结构来维护节点的顺序的,默认是按插入顺序维护的,每个节点都进行了双向连接。head指向插入的第一个节点,tail指向最后一个节点

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

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

克隆分为深拷贝和浅拷贝, 具体的拷贝实现需要用户自己根据对象的特性来实现, 集合类又是一个容器, 会装载不同的对象(各种各样的). 不可能每个对象都实现克隆,

序列化也是同样的道理。

虽然List没有继承序列化和克隆接口,但是它的子类ArrayList都继承了这两个接口。 并且根据自己的特性对这两个接口的实现都进行了自己的优化

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

Iterator 是可以遍历集合的对象,为各种容器提供了公共的操作接口,隔离对容器的遍历操作和底层实现,从而解耦。

缺点是增加新的集合类需要对应增加新的迭代器类,迭代器类与集合类成对增加。

17.Iterator和Listlterator的区别是什么?

iterator用于遍历所有类型的集合

ListIterator只能用来遍历List类型的集合

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

数组Array是在初始化的时候固定长度的,而ArrayList初始化时没有给定长度的话会有默认长度。

场景:事先已经预知需要存储的长度时使用array,长度不确定时使用ArrayList

19.Java集合类框架的最佳实践有哪些?

1.根据应用需要正确选择要使用的集合类型对性能非常重要,比如:假如知道元素的大小是固定的,那么选用Array类型而不是ArrayList类型更为合适。

2.有些集合类型允许指定初始容量。因此,如果我们能估计出存储的元素的数目,我们可以指定初始容量来避免重新计算hash值或者扩容等。

3.为了类型安全、可读性和健壮性等原因总是要使用泛型。同时,使用泛型还可以避免运行时的ClassCastException。

4.使用JDK提供的不变类(immutable class)作为Map的键可以避免为我们自己的类实现hashCode()和equals()方法。

5.编程的时候接口优于实现

6.底层的集合实际上是空的情况下,返回为长度是0的集合或数组而不是null。

20.Comparable和Comparator接口是干什么的?列出它们的区别

Comparable和Comparator都是用来对引用类型进行自定义的比较的。

Comparable是定义在类的内部的类实现Comparable接口重写其中的compare方法自定义排序规则

Comparator可以定义在类的外部实现ComparaTo方法自定已排序规则即可。

21.Collection和 Collections的区别。

Collection是一个接口

Comparable是定义在类的内部的类实现Comparable接口重写其中的compare方法自定义排序规则

Comparator可以定义在类的外部实现ComparaTo方法自定已排序规则即可。

21.Collection和 Collections的区别。

Collection是一个接口

Collections为Collection接口的实现了提供了相应的一些方法例如:sort() 自动将集合中元素排序(默认升序),集合中的对象要具备排序能力 shuffle() 打乱数组中元素 reverse() 将集合中元素倒置

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值