21个Java Collections面试问答
java collections框架是java编程语言的核心api之一。
这是java面试问题的重要主题之一。在这里,我列出了一些重要的java集合面试问题和解答,以帮助您进行面试。这直接来自我14年以上的java编程经验。
1、java 8中与collections相关的功能是什么?
java 8对 collection api 进行了重大更改。一些更改是:
- java stream api 用于集合类,以支持顺序处理和并行处理
- iterable 接口中的默认方法foreach(),可用于迭代集合。与 lambda 表达式一起使用时,它非常有用,因为其参数 consumer 是函数接口。
- collections api 改进,如在
iterator
接口中的foreachremaining(consumer action)
,mapreplaceall()
,compute()
,merge()
方法。
2、什么是 java collections framework?列出 collections 框架的一些好处?
每个编程语言都使用集合,和最初的java版本包含几个集合类:vector,stack,hashtable和array。但是从较高的范围和用法来看,java 1.2提出了collections framework,该框架将所有collections接口,实现和算法分组。
java的集合通过使用泛型和并发集合类进行线程安全操作已经走了很长一段路。它还包括在java的并发包中的阻塞接口及其实现。
collections 框架的一些好处是;
- 通过使用核心集合类而不是实现我们自己的集合类来减少开发工作。
- 通过使用通过良好测试的集合框架类,可以提高代码质量。
- 通过使用jdk附带的集合类,减少了代码维护工作。
- 可重用性和互操作性
3、集合框架中泛型的好处是什么?
java 1.5带有泛型,所有集合接口和实现都大量使用它。泛型允许我们提供集合可以包含的object的类型,因此,如果您尝试添加其他类型的任何元素,则引发编译时错误。
这样可以避免在运行时发生classcastexception,因为您将在编译时收到错误。由于我们不需要使用强制转换和_实例化_运算符,因此泛型也使代码更干净。
4、java collections framework的基本接口是什么?
collection 表示集合层次结构的根。collection表示一组元素的对象。java平台不提供此接口的任何直接实现。
set是一个不能包含重复元素的集合。此接口对数学集合的抽象进行建模,并表示集合,例如纸牌集合。
list是一个有序的集合,可以包含重复的元素。您可以从其索引访问任何元素。该列表更像是具有动态长度的数组。
一个map是键映射到值的对象。映射不能包含重复的键:每个键最多可以映射到一个值。
其他一些接口queue
,dequeue
,iterator
,sortedset
,sortedmap
和listiterator
。
5、为什么collection不实现cloneable和serializable接口?
collection接口指定为一组元素对象。元素的维护方式取决于collection的具体实现。例如,某些collection实现(例如list)允许重复元素,而其他实现(例如set)则不允许重复元素。
许多collection实现都有cloneable方法。但是,将其包含在collection的所有实现中没有意义。这是因为collection是抽象表示。重要的是。
在处理实际实现时,克隆或序列化的语义及其含义都会发挥作用。因此具体的实现应决定如何克隆或序列化它,甚至可以对其进行克隆或序列化。
因此,在所有实现中强制进行克隆和序列化的灵活性较差,限制也更大。具体实现应决定是否可以克隆或序列化。
6、为什么map接口没有实现collection接口?
尽管map接口及其实现是collections framework的一部分,但map不是集合,集合也不是map。因此,map扩展collection是没有意义的,反之亦然。
如果map扩展了collection接口,那么元素在哪里?该映射包含key-value对,并且提供了一些方法来检索键或值的列表作为collection,但它不适合“元素组”范式。
7、什么是迭代器?
迭代器接口提供了对任何collection进行迭代的方法。我们可以使用_iterator()_方法从collection中获取迭代器实例。在java collections framework中,迭代器代替了枚举。迭代器允许调用者在迭代过程中从基础集合中删除元素。java collection迭代器提供了遍历集合元素的通用方法,并实现了iterator design pattern。
8、enumeration和iterator接口之间有什么区别?
枚举的速度是iterator的两倍,并且使用的内存更少。枚举是非常基本的,适合基本需求。但是,与enumeration相比,iterator安全得多,因为它始终拒绝其他线程修改被其迭代的集合对象。
在java collections framework中,迭代器代替了枚举。迭代器允许调用者从基础集合中删除enumeration无法实现的元素。迭代器方法名称已得到改进,以使其功能更清晰。
9、为什么没有像iterator.add()这样的方法将元素添加到集合中?
考虑到iterator的约定不保证迭代顺序,原因尚不清楚。但是请注意,listiterator确实提供了add操作,因为它确实保证了迭代的顺序。
10、为什么iterator没有不移动光标就直接获取下一个元素的方法?
可以在当前iterator接口的顶部实现它,但是由于很少使用它,因此将它包含在每个人都必须实现的接口中没有意义。
11、iterator和listiterator有什么区别?
- 我们可以使用iterator遍历set和list集合,而listiterator只能与lists一起使用。
- iterator只能向前移动,而listiterator可以用于两个方向。
- listiterator继承自iterator接口,并具有其他功能,例如添加元素,替换元素,获取上一个和下一个元素的索引位置。
12、有哪些不同的方法可以遍历列表?
我们可以通过两种不同的方式遍历列表-使用迭代器和使用for-each循环。
list <string> strlist = new arraylist<>(); for(string obj:strlist){ system.out.println(obj); } iterator<string> it= strlist.iterator(); while(it.hasnext()){ string obj = it.next(); system.out.println(obj); }
使用迭代器更加线程安全,因为它可以确保如果基础列表元素被修改,它将抛出异常concurrentmodificationexception
。
13、您对iterator fail-fast属性有什么了解?
每当我们尝试获取下一个元素时,迭代器fail-fast属性都会检查基础集合的结构是否有任何修改。如果找到任何修改,则抛出concurrentmodificationexception
。除了并行并发类(例如concurrenthashmap和copyonwritearraylist)之外,collection类中iterator的所有实现在设计上都是fail-fast的。
14、fail-fast和fail-safe之间有何区别?
iterato fail-safe属性可与基础集合的克隆一起使用,因此不受集合中任何修改的影响。按照设计,java.util
包中的所有集合类都是fail-fast的,而其中的集合类java.util.concurrent
是fail-safe的。
fail-fast迭代器会抛出concurrentmodificationexception,而fail-safe迭代器绝不会抛出concurrentmodificationexception。
15、如何在迭代集合时避免concurrentmodificationexception?
我们可以使用并发集合类来避免concurrentmodificationexception
在集合上进行迭代,例如使用copyonwritearraylist而不是arraylist。
16、为什么没有iterator接口的具体实现?
iterator接口声明了用于迭代集合的方法,但是其实现是collection实现类的责任。每个返回迭代器以进行遍历的集合类都有其自己的iterator实现嵌套类。
这使集合类可以选择迭代器是fail-fast还是fail-safe的。例如,arraylist迭代器是fail-fast的,而copyonwritearraylist迭代器是fail-safe的。
17、什么是unsupportedoperationexception?
unsupportedoperationexception
是用于指示不支持该操作的异常。它广泛用于在jdk类,在集合框架java.util.collections.unmodifiablecollection
抛出该异常所有add
和remove
操作。
18、hashmap如何在java中工作?
hashmap在map.entry
静态嵌套类实现中存储键值对。hashmap使用哈希算法,并在put
和get
方法中使用hashcode()和equals()方法。
当我们put
通过传递键值对来调用方法时,hashmap使用带有哈希值的key hashcode()来查找存储键值对的索引。该条目存储在linkedlist中,因此,如果已经存在一个条目,则使用equals()方法检查传递的键是否已存在,如果是,它将覆盖该值,否则它将创建一个新条目并存储此键值条目。
当我们get
通过传递key来调用method时,它再次使用hashcode()在数组中找到索引,然后使用equals()方法找到正确的entry并返回其值。下图将清楚地解释这些细节。
有关hashmap的其他重要信息是容量,负载因子,阈值大小调整。hashmap的初始默认容量为16,负载系数为0.75。阈值是容量乘以负载因子,并且如果map大小大于阈值,则每当我们尝试添加条目时,hashmap都会将map的内容重新映射为容量更大的新数组。容量始终是2的乘方,因此,如果您知道需要存储大量的键值对,例如在缓存数据库中的数据时,最好使用正确的容量和负载因子来初始化hashmap。 。
19、hashcode()和equals()方法的重要性是什么?
hashmap使用key对象的hashcode()和equals()方法来确定放置键值对的索引。当我们尝试从hashmap中获取价值时,也会使用这些方法。如果这些方法的实现不正确,则两个不同的key可能会产生相同的hashcode()和equals()输出,在这种情况下,hashmap不会考虑将它们存储在不同的位置,而是将其覆盖并覆盖它们。
同样,所有不存储重复数据的集合类都使用hashcode()和equals()查找重复项,因此正确实现它们非常重要。equals()和hashcode()的实现应遵循以下规则。
- 如果
o1.equals(o2)
,那么o1.hashcode() == o2.hashcode()
应该永远如此true
。 - 如果
o1.hashcode() == o2.hashcode
是真的,这并不意味着o1.equals(o2)
会true
。
20、我们可以使用任何类作为map键吗?
我们可以将任何类用作map key,但是在使用它们之前应考虑以下几点。
- 如果该类重写equals()方法,则它也应该重写hashcode()方法。
- 对于所有实例,该类应遵循与equals()和hashcode()关联的规则。这些规则请参考前面的问题。
- 如果equals()中未使用类字段,则不应在hashcode()方法中使用它。
-
用户定义的键类的最佳实践是使其不可变,以便可以将hashcode()值缓存起来以提高性能。不可变的类还确保hashcode()和equals()将来不会更改,这将解决任何可变性问题。
例如,假设我有一个mykey
用于hashmap键的类。//传递的mykey name参数用于equals()和hashcode() mykey key = new mykey("pankaj"); //假定hashcode=1234 myhashmap.put(key, "value"); // 下面的代码将更改equals()和hashcode()的key // 但是它的位置不会改变 key.setname("amit"); //假定新的hashcode=7890 //下面将返回null,因为hashmap将尝试查找键 //与存储在同一索引中,但由于密钥发生了变化, //不匹配,返回空。 myhashmap.get(new mykey("pankaj"));
这就是为什么string和integer大多用作hashmap键的原因。
21、map接口提供哪些不同的collection视图?
map接口提供了三个集合视图:
-
set
keyset() :返回此映射中包含的键的set视图。该集合由map支持,因此对map的更改会反映在集合中,反之亦然。如果在对集合进行迭代时修改了映射(通过迭代器的remove操作除外),则迭代的结果不确定。该集合支持元素删除,该元素通过迭代器remove,set.remove,removeall,retainall和clear操作从映射中删除相应的映射。它不支持add或addall操作。 -
collection
values() :返回此映射中包含的值的collection视图。集合由map支持,因此对map的更改会反映在集合中,反之亦然。如果在对集合进行迭代时修改了映射(通过迭代器的remove操作除外),则迭代结果不确定。集合支持元素删除,该元素通过迭代器remove,collection.remove,removeall,retainall和clear操作从映射中删除相应的映射。它不支持add或addall操作。 - set <map.entry <k,v >> entryset():返回此映射中包含的映射的set视图。该集合由map支持,因此对map的更改会反映在集合中,反之亦然。如果在对集合进行迭代时修改了映射(通过迭代器的remove操作或迭代器返回的映射条目上的setvalue操作除外),则迭代的结果不确定。该集合支持元素删除,该元素通过迭代器remove,set.remove,removeall,retainall和clear操作从映射中删除相应的映射。它不支持add或addall操作。
“不积跬步,无以至千里”,希望未来的你能:有梦为马 随处可栖!加油,少年!
关注公众号:「java 知己」,每天更新java知识哦,期待你的到来!
- 发送「group」,与 10 万程序员一起进步。
- 发送「面试」,领取batj面试资料、面试视频攻略。
- 发送「玩转算法」,领取《玩转算法》系列视频教程。
- 千万不要发送「1024」...