关于集合的笔试面试题

1.Java集合类框架的基本接口有哪些?区别是什么?


总共有两大接口:Collection Map ,一个元素集合,一个是键值对集合; 其中ListSet接口继承了Collection接口,List是有序元素集合,Set是无序元素集合;ArrayList、 LinkedList Vector实现了List接口,HashSet、LinkedHashSetTreeSet实现了Set接口,这几个都比较常用; HashMap HashTable实现了Map接口,并且HashTable是线程安全的,但是HashMap性能更好;

2.什么是迭代器(Iterator)?
迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。Java中的Iterator功能比较简单,并且只能单向移动:对已集合类中的任何一个实现类,都可以返回这样一个Iterator对象。跟循环差不多

好处是可以适合用于任何一个类,而且java也对它进行了优化,比直接用index访问快一点。迭代器是一种模式,它可以使得对于序列类型的数据结构的遍历行为与被遍历的对象分离,迭代器相当于有个指针,每次调用hasNext()方法如果返回值是true,说明有下一个元素,再执行next()方法获得该元素的值.

在迭代器Iteartor接口中,有以下3个方法:

1.hasNext() 该方法英语判断集合对象是否还有下一个元素,如果已经是最后一个元素则返回false

2.next() 把迭代器的指向移到下一个位置,同时,该方法返回下一个元素的引用

3.remove()  从迭代器指向的Collection中移除迭代器返回的最后一个元素,该操作使用的比较少。

注意:从Java5.0开始,迭代器可以被foreach循环所替代,但是foreach循环的本质也是使用Iterator进行遍历的。

扫描二维码关注公众号,回复: 1305715 查看本文章

 

3.Iterator和ListIterator的区别是什么?

1.ListIterator只能用于ListIterator是通用的

2.Iterator容易引起并发修改异常问题,而ListIterator可以避免线程安全问题的发生,因为其有内置的add()等修改集合的方法。

4.Java中的HashMap的工作原理是什么?

首先比较一下equals()和hashcode()方法的不同点:

equals:是否同一个对象实例。注意,是“实例”。比如String s = new String("test");  s.equals(s), 这就是同一个对象实例的比较;

等号(==):对比对象实例的内存地址(也即对象实例的ID),来判断是否是同一对象实例;又可以说是判断对象实例是否物理相等;

Hashcode:我觉得可以这样理解:并不是对象的内存地址,而是利用hash算法,对对象实例的一种描述符(或者说对象存储位置的hash算法映射,即用HashCode方法来描述对象存储位置bucket的位置——对象实例的哈希码

为什么需要使用Hashcode,可以从Java集合的常用需求来描述:

Java中的集合(Collection)有两类,一类是List,再有一类是Set。前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。那么这里就有一个比较严重的问题了:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?这就是 Object.equals方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000equals方法。这显然会大大降低效率。
于是,Java采用了哈希表的原理。哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。可以这样简单理解,hashCode方法实际上返回的就是对象存储位置的映像。这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就能定位到它应该放置的存储位置。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就表示发生冲突了,散列表对于冲突有具体的解决办法(主要有四种方法:1.开放定址法;2.再散列函数法;3.链地址法;4.公共溢出区法。各种方法具体的优缺点参见:https://www.cnblogs.com/cing/p/8821389.html),但最终还会将新元素保存在适当的位置。这样一来,实际调用equals方法的次数就大大降低了,几乎只需要一两次。

HashMap基于Map接口实现、允许null/值、非同步、不保证有序(比如插入的顺序)、也不保证序不随时间变化。在HashMap中有两个很重要的参数,容量(Capacity)和负载因子(Load factor)。Capacity就是bucket(桶)的大小,Load factor就是bucket填满程度的最大比例一般是0.75)

HashMap是基于hashing的原理,我们使用put(key, value)存储对象到HashMap中,使用get(key)HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket位置来储存Entry对象。HashMap是在bucket中储存键对象和值对象,作为Map.Entry

当两个对象的hashcode相同会发生什么?因为hashcode相同,所以它们的bucket位置相同‘碰撞’会发生。因为HashMap使用链表存储对象,这个Entry(包含有键值对的Map.Entry对象)会存储在链表中。

如果两个键的hashcode相同,如何获取值对象?当我们调用get()方法,HashMap会使用键对象的hashcode找到bucket位置,然后会调用keys.equals()方法去找到链表中正确的节点,最终找到要找的值对象。

如果HashMap的大小超过了负载因子(load factor)定义的容量,怎么办?默认的负载因子大小为0.75,也就是说,当一个map填满了75%bucket时候,和其它集合类(ArrayList)一样,将会创建原来HashMap大小的两倍的bucket数组,来重新调整map的大小,并将原来的对象放入新的bucket数组中。这个过程叫作rehashing,因为它调用hash方法找到新的bucket位置。

重新调整HashMap大小存在什么问题呢?在多线程的环境下,当重新调整HashMap大小的时候,存在条件竞争,因为如果两个线程都发现HashMap需要重新调整大小了,它们会同时试着调整大小。在调整大小的过程中,存储在链表中的元素的次序会反过来,因为移动到新的bucket位置的时候,HashMap并不会将元素放在链表的尾部,而是放在头部,这是为了避免尾部遍历(tail traversing)。如果条件竞争发生了,那么就死循环了。这个时候,你可以质问面试官,为什么这么奇怪,要在多线程的环境下使用HashMap呢?


5.HashMap和Hashtable有什么区别?

1 HashMap不是线程安全的

     HashMapmap接口的子类,是将键映射到值的对象,其中键和值都是对象,并且不能包含重复键,但可以包含重复值。HashMap允许null keynull value,而hashtable不允许。

2   HashTable是线程安全。

HashMapHashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key,由于非线程安全,效率上可能高于Hashtable

HashMap允许将null作为一个entrykey或者value,而Hashtable不允许。

HashMapHashtablecontains方法去掉了,改成containsvaluecontainsKey。因为contains方法容易让人引起误解。 Hashtable继承自Dictionary类,而HashMapJava1.2引进的Map interface的一个实现。 最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步。 HashtableHashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差


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

Array 可以包含基本类型和对象类型,ArrayList 只能包含对象类型。Array 大小是固定的,ArrayList 的大小是动态变化的。ArrayList 提供了更多的方法和特性,比如:addAll()removeAll()iterator()等等。对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。

 

7.ArrayList和LinkedList有什么区别?删除它们的一个元素,底层原理分别是什么?

ArrayList LinkedList 都实现了 List 接口,他们有以下的不同点:ArrayList 是基于索引的数据接口,它的底层是数组。它可以以 O(1)时间复杂度对元素进行随机访问。与此对应,LinkedList 是以元素列表的形式存储它的数据,每一个元素都和它的前 一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是 O(n)。相对于 ArrayList LinkedList 的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引。LinkedList ArrayList 更占内存,因为 LinkedList 为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。

 

8.HashSet和TreeSet有什么区别?

相同点:

单列集合,元素不可重复

不同点

1. 底层存储的数据结构不同

    HashSet底层用的是HashMap哈希表结构存储,而TreeSet底层用的是TreeMap树结构存储

2.存储时保证数据唯一性依据不同

   HashSet是通过复写hashCode()方法和equals()方法来保证的,而HashSet通过Compareable接口的compareTo()方法来保证的

3.有序性不一样

 HashSet无序,TreeSet有序

 存储原理:

   HashSet:底层数据结构是哈希表,本质就是对哈希值的存储,通过判断元素的hashCode方法和equals方法来保证元素的唯一性,当hashCode值不相同,就直接存储了,不用在判断equals了,当hashCode值相同时,会在判断一次euqals方法的返回值是否为true,如果为true则视为用一个元素,不用存储,如果为false,这些相同哈希值不同内容的元素都存放一个桶里(当哈希表中有一个桶结构,每一个桶都有一个哈希值)

  TreeSet:底层的数据结构是二叉树,可以对Set集合中的元素进行排序,这种结构,可以提高排序性能根据比较方法的返回值确定的,只要返回的是0.就代表元素重复

 

9.什么是面向对象?

将复杂的事情简单化。

2:面向对象将以前的过程中的执行者,变成了指挥者。

3:面向对象这种思想是符合现在人们思考习惯的一种思想。

2、面向对象的三大特征:封装,继承、多态

10.Collection 和 Collections的区别?

Collection是集合类的上级接口,继承与他有关的接口主要有ListSet

Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全等操作

 

11.HashMap,LinkedMap,TreeMap的区别.

Map 主要用于存储键(key)(value)对,根据键得到值,因此键不允许键重复,但允许值重复。

HashMap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。HashMap最多只允许一条记录的键为Null;允许多条记录的值为 Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。如果需要同步,可以用 CollectionssynchronizedMap方法使HashMap具有同步的能力。                                                                          
LinkedHashMap也是一个HashMap,但是内部维持了一个双向链表,可以保持顺序

TreeMap 可以用于排序

12.ArrayList底层是数组,那么为什么数组长度是固定的而集合长度是可变的?怎么实现?

ArrayList底层是变长数组维护的,不需要定义其大小,如果长度不够了就会自动扩展为原来长度的一倍,数组的大小在定义的时候已经是个固定的值,不会自动扩展,数组的效率比集合的效率高,各有侧重点。


参考:如何计算时间复杂度:http://blog.csdn.net/firefly_2002/article/details/8008987


 

 

猜你喜欢

转载自blog.csdn.net/weixin_41768263/article/details/80445859