面试题:java集合

1、说说List、Set、Map的区别?

List:可以存储一组有序可重复的对象。
Set:可以存储一组不重复的对象。
Map:以K,V键值对存储。在Map中通过key去找value。Map中的Key不能重复,value可以重复。

2、Arraylist 与 LinkedList 区别?

问到这个问题得从多个角度分析,例如线程是否安全、底层数据结构、增删改查速度比较、内存空间占用情况、是否实现了RandomAccess接口(重要)等等。

线程是否安全:ArrayList和LinkedList都是线程不安全的类。
底层数据结构:Array List底层使用数组实现,LinkedList底层使用双向链表实现(jdk1.6之前使用双向循环链表)。
增删改查速度比较:ArrayList因为使用数组,所以有索引这个概念,更适合应用在查询和修改上,LinkedList因为使用链表实现,所以增删效率会快一些。
内存空间占用:因为LinkedList中的链表节点除了要维护node还要维护pre和next,所以内存占用会比ArrayList要多。
是否实现RandomAccess接口:ArrayList实现了RandomAccess接口,而LinkedList没有,RandomAccess的意思是随机访问,这个接口是一个标识,没有其他功能,这个标识的作用比如我们在使用binarySearch()这个方法的时候,会判断这个List是否实现了RandomAccess接口,如果实现了,会优先使用for循环,其次使用foreach;如果没有实现RandomAccess接口,会优先选择iterator遍历(foreach遍历底层也是通过iterator实现的,),大size的数据,千万不要使用普通for循环。

3、ArrayList 与 Vector 区别呢?为什么要用Arraylist取代Vector呢?

Vector线程安全,但是并发效率太慢,ArrayList线程不安全,但是并发效率快。如果要线程安全的List的类使用CopyOnWriteArrayList,底层使用了读写分离的思想。

4、说一说 ArrayList 的扩容机制吧

ArrayList可以有两种初始化方式,如果不指定数据容量,底层会自动创建一个数组容量为10的数组,如果我们在构造器中输入参数,会初始化参数量的数组。ArrayList在进行扩容的时候会先创建一个比原来数组大1.5倍的数组,再把原先数组中的数据一个个拷贝过去,ArrayList再引用扩容后的数组。

5、HashMap 和 Hashtable 的区别

从多个维度去讨论,线程是否安全、效率、底层数据结构、扩容机制、是否支持null值添加。

线程是否安全:HashTable线程安全,HashMap线程不安全
效率:HashMap并发高、HashTable并发低
底层数据结构:HashMap使用数组+链表+红黑树实现,当hash冲突链表的阈值大于8的时候会转成红黑树,HashTable没有这样的机制。
扩容机制:HashMap默认容量是16,当扩容的时候会变成2n倍,HashTable的默认容量是11,扩容的时候会变成2n+1倍。
是否支持null值添加:HashMap可以支持key存放null,但只能有一个,value都可以存放null;HashTable的key和value都不能存放null,如果放了访问会空指针异常。

如果要使用线程安全的Map,请使用ConcurrentHashMap。

6、HashMap 和 HashSet区别

HashSet不可以存放重复的对象,HashMap以K-V键值对存放数据。HashSet底层是HashMap,只存key,value都存的是null。

7、HashSet如何检查重复

向HashSet中存放数据会先判断数据的hashcode,如果Set中没有该hashcode,则代表里面没有该元素,可以添加,如果有hashcode相等再判断equals方法,如果相等就代表有该元素,不能添加。

8、HashMap的底层实现

jdk1.7之前HashMap的实现是基于数组+链表实现,在发生hash冲突的时候会将数组的元素以链表方式存放。在jdk1.8之后HashMap实现基于数组+链表+红黑树,在发生hash冲突后会把元素以链表方式存储,但当链表长度大于阈值8的时候,会将链表转换为红黑树,为什么是红黑树因为红黑树是平衡的二叉树,如果用普通的二叉树在极端情况下会退化成链表。

9、HashMap 多线程操作导致死循环问题

主要原因是在并发下的Rehash会造成元素之间形成循环链表导致死循环,但在jdk1.8之后解决了这个问题,但HashMap在多线程操作下还可以会有数据丢失问题。所以如果我们要在多线程并发操作还是推荐用ConcurrentHashMap。

10、ConcurrentHashMap 和 Hashtable 的区别

从数据结构、实现线程安全的方式讨论。首先ConcurrentHashMap和Hashtable都是线程安全的类。

数据结构:jdk1.7以前ConcurrentHashMap基于分段数组+链表+红黑树实现的,jdk1.8之后和HashMap一样基于数组+链表+红黑树实现。Hashtable则一直是数组+链表实现。
实现线程安全的方式:Hashtable是把每个方法都加上synchronized关键字,效率很低。ConcurrentHashMap是基于分段锁实现的,在jdk1.7之前基于分段数组,线程拿到锁只是拿到一块资源,另外的资源给别的线程拿,提高了并发。到了 JDK1.8 的时候已经摒弃了Segment(分段)的概念,而是直接用 Node 数组+链表+红黑树的数据结构来实现,并发控制使用 synchronized 和 CAS 来操作。(JDK1.6以后 对 synchronized锁做了很多优化) 整个看起来就像是优化过且线程安全的 HashMap,虽然在JDK1.8中还能看到 Segment 的数据结构,但是已经简化了属性,只是为了兼容旧版本。

11、comparable 和 Comparator的区别

comparable接口实际上是出自java.lang包 它有一个 compareTo(Object obj)方法用来排序。
comparator接口实际上是出自 java.util 包它有一个compare(Object obj1, Object obj2)方法用来排序。

以面向对象的方面来思考,假如突然有个需求要对学生按照成绩进行排序应该实现Comparator,因为学生还有可能以学号排序等等,学生不存在可排序这个性质,只有成绩、学号有可排序这个性质。我们可以把成绩学号看成一个类的话就可以实现comparable接口。

12、集合框架底层数据结构总结

Collection

List
Arraylist: Object数组
Vector: Object数组
LinkedList: 双向链表(JDK1.6之前为循环链表,JDK1.7取消了循环)
CopyOnWriteArrayList:线程安全的基于读写分离思想的ArrayList

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: 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的
TreeMap: 红黑树(自平衡的排序二叉树)

13、如何选用集合?

这种问题就介绍每个集合的特性再介绍具体集合线程是否安全之类的,最后说结合业务考虑。

List是存放一组可重复的有序的对象。
Set存放不可重复的对象。
Map存放K-V键值对。
根据业务需求来使用对应集合。
List我们可以选ArrayList和LinkedList和CopyOnWriteArrayList,介绍对应的区别,是否线程安全。
Set介绍HashSet和TreeSet,要求线程安全可以用ConcurrentHashSet。
Map介绍ConcurrentHashMap和HashMap。
再说根据业务考虑。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
整理了网上的一些java面试题目,很全很强大 面向对象的特征有哪些方面 1. 抽象:抽象就是忽略一个主题中与当前目标2. 无关的那些方面,3. 以便更充分地注意与当前目标4. 有关的方面。抽象并不5. 打算了解全部问题,而6. 只是选择其中的一部分,7. 暂时不 8. 用部分细节。抽象包括两个方面,9. 一是过程抽象,10. 二是数据抽象。 11. 继承:继承是一种联结类的层次模型,12. 并且允许和鼓励类的重用,13. 它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,14. 这个过程称为类继承。新类继承了原始类的特性,15. 新类称为原始类的派生类(子类),而16. 原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,17. 并且类可以修改或增加新的方法使之更适合特殊的需要。 18. 封装:封装是把过程和数据包围起来,19. 对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念,20. 即现实世界可以被描绘成一系列完全自治、封装的对象,21. 这些对象通过一个受保护的接口访问其他对象。 22. 多态性:多态性是指23. 允许不同24. 类的对象对同25. 一消息作出响应。多态性包括参数化多态性和包含多态性。多态性语言具有灵活、抽象、行为共享、代码共享的优势,26. 很好的解决了应用程序函数同27. 名28. 问题。 2、String是最基本的数据类型吗? 基本数据类型包括byte、int、char、long、float、double、boolean和short。 java.lang.String类是final类型的,因此不可以继承这个类、不能修改这个类。为了提高效率节省空间,我们应该用StringBuffer类 3、int 和 Integer 有什么区别 Java 提供两种不同的类型:引用类型和原始类型(或内置类型)。Int是java的原始数据类型,Integer是java为int提供的封装类。Java为每个原始类型提供了封装类。 原始类型封装类booleanBoolean charCharacter byteByte shortShort intInteger longLong floatFloat doubleDouble 引用类型和原始类型的行为完全不同,并且它们具有不同的语义。引用类型和原始类型具有不同的特征和用法,它们包括:大小和速度问题,这种类型以哪种类型的数据结构存储,当引用类型和原始类型用作某个类的实例数据时所指定的缺省值。对象引用实例变量的缺省值为 null,而原始类型实例变量的缺省值与它们的类型有关。 4、String 和StringBuffer的区别 JAVA平台提供了两个类:String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而这个StringBuffer类提供的字符串进行修改。当你知道字符数据要改变的时候你就可以使用StringBuffer。典型地,你可以使用 StringBuffers来动态构造字符数据。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值