⾯试题-Java基础-集合和数组
1.Java集合类框架的基本接⼝有哪些?
集合类接⼝指定了⼀组叫做元素的对象。集合类接⼝的每⼀种具体的实现类都可以选择以它⾃⼰的⽅式对元素进⾏保存和排序。有的集合类允许重复的键,有些不允许。
Java集合类提供了⼀套设计良好的⽀持对⼀组对象进⾏操作的接⼝和类。Java集合类⾥⾯最基本的接⼝有:
Collection:代表⼀组对象,每⼀个对象都是它的⼦元素。
Set:不包含重复元素的Collection。
List:有顺序的collection,并且可以包含重复元素。
Map:可以把键(key)映射到值(value)的对象,键不能重复。
2.为什么集合类没有实现Cloneable和Serializable接⼝?
克隆(cloning)或者是序列化(serialization)的语义和含义是跟具体的实现相关的。因此,应该由集合类的具
体实现来决定如何被克隆或者是序列化。
3.什么是迭代器(Iterator)?
Iterator接⼝提供了很多对集合元素进⾏迭代的⽅法。每⼀个集合类都包含了可以返回迭代器实例的
迭代⽅法。迭代器可以在迭代的过程中删除底层集合的元素,但是不可以直接调⽤集合的
remove(Object Obj)删除,可以通过迭代器的remove()⽅法删除。
4.Iterator和ListIterator的区别是什么?
下⾯列出了他们的区别:
Iterator可⽤来遍历Set和List集合,但是ListIterator只能⽤来遍历List。
Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。
ListIterator实现了Iterator接⼝,并包含其他的功能,⽐如:增加元素,替换元素,获取前⼀个和后⼀个元素的索引,等等。
5.快速失败(fail-fast)和安全失败(fail-safe)的区别是什么?
Iterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响。java.util包下⾯的所有的集合类都是快速失败的,⽽urrent包下⾯的所有的类都是安全失败的。快速失败的迭代器会抛出ConcurrentModificationException异常,⽽安全失败的迭代器永远不会抛出这样的异常。
6.Java中的HashMap的⼯作原理是什么?
Java中的HashMap是以键值对(key-value)的形式存储元素的。HashMap需要⼀个hash函数,它使⽤hashCode()和equals()⽅法来向集合/从集合添加和检索元素。当调⽤put()⽅法的时候,HashMap会计算key的hash值,然后把键值对存储在集合中合适的索引上。如果key已经存在了,value会被更新成新值。HashMap的⼀些重要的特性是它的容量(capacity),负载因⼦(load factor)和扩容极限(threshold resizing)。7.hashCode()和equals()⽅法的重要性体现在什么地⽅?
Java中的HashMap使⽤hashCode()和equals()⽅法来确定键值对的索引,当根据键获取值的时候也会⽤到这两个⽅法。如果没有正确的实现这两个⽅法,两个不同的键可能会有相同的hash值,因此,可能会被集合认为是相等的。⽽且,这两个⽅法也⽤来发现重复元素。所以这两个⽅法的实现对HashMap的精确性和正确性是⾄关重要的。
8.HashMap和Hashtable有什么区别?
HashMap和Hashtable都实现了Map接⼝,因此很多特性⾮常相似。但是,他们有以下不同点:
HashMap允许键和值是null,⽽Hashtable不允许键或者值是null。
Hashtable是同步的,⽽HashMap不是。因此,HashMap更适合于单线程环境,⽽Hashtable适合于多线程环境。
HashMap提供了可供应⽤迭代的键的集合,因此,HashMap是快速失败的。另⼀⽅⾯,Hashtable提供了对键的列举(Enumeration)。
⼀般认为Hashtable是⼀个遗留的类。
9.数组(Array)和列表(ArrayList)有什么区别?什么时候应该使⽤Array⽽不是ArrayList?
下⾯列出了Array和ArrayList的不同点:
Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。
Array⼤⼩是固定的,ArrayList的⼤⼩是动态变化的。
java集合排序怎么实现ArrayList提供了更多的⽅法和特性,⽐如:addAll(),removeAll(),iterator()等等。
对于基本类型数据,集合使⽤⾃动装箱来减少编码⼯作量。但是,当处理固定⼤⼩的基本数据类型的时
候,这种⽅式相对⽐较慢。
10.ArrayList和LinkedList有什么区别?
ArrayList和LinkedList都实现了List接⼝,他们有以下的不同点:
ArrayList是基于索引的数据接⼝,它的底层是数组。它可以以O(1)时间复杂度对元素进⾏随机访问。与此对应,LinkedList是以元素列表的形式存储它的数据,每⼀个元素都和它的前⼀个和后⼀个元素链接在⼀起,在这种情况下,查某个元素的时间复杂度是O(n)。
相对于ArrayList,LinkedList的插⼊,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算⼤⼩或者是更新索引。
LinkedList⽐ArrayList更占内存,因为LinkedList为每⼀个节点存储了两个引⽤,⼀个指向前⼀个元素,⼀个指向下⼀个元素。
也可以参考ArrayList vs. LinkedList。
11.Comparable和Comparator接⼝是⼲什么的?列出它们的区别。
Java提供了只包含⼀个compareTo()⽅法的Comparable接⼝。这个⽅法可以个给两个对象排序。具体来说,它返回负数,0,正数来表明输⼊对象⼩于,等于,⼤于已经存在的对象。
Java提供了包含compare()和equals()两个⽅法的Comparator接⼝。compare()⽅法⽤来给两个输⼊参数排序,返回负数,0,正数表明第⼀个参数是⼩于,等于,⼤于第⼆个参数。equals()⽅法需要⼀个对象作为参数,它⽤来决定输⼊参数是否和comparator相等。只有当输⼊参数也是⼀个comparator并且输⼊参数和当前comparator的排序结果是相同的时候,这个⽅法才返回true。
12.什么是Java优先级队列(Priority Queue)?
PriorityQueue是⼀个基于优先级堆的⽆界队列,它的元素是按照⾃然顺序(natural order)排序的。在创建的时候,我们可以给它提供⼀个负责给元素排序的⽐较器。PriorityQueue不允许null值,因为他们没有⾃然顺序,或者说他们没有任何的相关联的⽐较器。最
后,PriorityQueue不是线程安全的,⼊队和出队的时间复杂度是O(log(n))。
13.你了解⼤O符号(big-O notation)么?你能给出不同数据结构的例⼦么?
⼤O符号描述了当数据结构⾥⾯的元素增加的时候,算法的规模或者是性能在最坏的场景下有多么好。
⼤O符号也可⽤来描述其他的⾏为,⽐如:内存消耗。因为集合类实际上是数据结构,我们⼀般使⽤⼤O符号基于时间,内存和性能来选择最好的实现。⼤O符号可以对⼤量数据的性能给出⼀个很好的说明。
14.如何权衡是使⽤⽆序的数组还是有序的数组?
有序数组最⼤的好处在于查的时间复杂度是O(log n),⽽⽆序数组是O(n)。有序数组的缺点是插⼊操作的时间复杂度是O(n),因为值⼤的元素需要往后移动来给新元素腾位置。相反,⽆序数组的插⼊时间复杂度是常量O(1)。
15.Java集合类框架的最佳实践有哪些?
根据应⽤的需要正确选择要使⽤的集合的类型对性能⾮常重要,⽐如:假如元素的⼤⼩是固定的,⽽且能事先知道,我们就应该⽤Array⽽不是ArrayList。
有些集合类允许指定初始容量。因此,如果我们能估计出存储的元素的数⽬,我们可以设置初始容量来避免重新计算hash值或者是扩容。为了类型安全,可读性和健壮性的原因总是要使⽤泛型。同时,使⽤泛型还可以避免运⾏时的ClassCastException。
使⽤JDK提供的不变类(immutable class)作为Map的键可以避免为我们⾃⼰的类实现hashCode()和equal
s()⽅法。
编程的时候接⼝优于实现。
底层的集合实际上是空的情况下,返回长度是0的集合或者是数组,不要返回null。
16.Enumeration接⼝和Iterator接⼝的区别有哪些?
Enumeration速度是Iterator的2倍,同时占⽤更少的内存。但是,Iterator远远⽐Enumeration安全,因为其他线程不能够修改正在被iterator遍历的集合⾥⾯的对象。同时,Iterator允许调⽤者删除底层集合⾥⾯的元素,这对Enumeration来说是不可能的。
17.HashSet和TreeSet有什么区别?
HashSet是由⼀个hash表来实现的,因此,它的元素是⽆序的。add(),remove(),contains()⽅法的时间复杂度是O(1)。
另⼀⽅⾯,TreeSet是由⼀个树形的结构来实现的,它⾥⾯的元素是有序的。因此,add(),remove(),contains()⽅法的时间复杂度是
O(logn)。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论