有关[Java集合]的面试题汇总

Java的集合

1.HashMap排序题

已知一个HashMap

2.集合的安全性问题

请问ArrayList,HashSet,HashMap是线程安全的吗?如果不是我想要线程安全的集合怎么办?

我们都看过上面那些集合的源码(如果没有那就看看吧),每个方法都没有加锁,显然都是线程不安全的.话有说过来如果他们安全了也就没有第二问了.
在集合中Vector和HashTable是线程安全的.你打开源码会发现其实就是把各自核心方法加上了synchronized关键字.
Collections工具类提供了相关的API,可以让上面那3个不安全的集合变为安全的.

Collections.synchronizedCollection(c);
Collections.synchronizedList(list);
Collections.synchronizedMap(m);
Collections.synchronizedSet(s);

上面几个函数都有对应的返回值类型,传入什么类型返回什么类型.打开源码其实实现原理非常简单,就是将集合的核心方法加上了synchronized关键字

3.List的三个子类的特点

  • ArrayList底层结构是数组,底层查询快,增删慢
  • LinkedList底层结构是链表型,增删快,查询慢
  • voctor底层结构是数组 它是线程安全的,增删慢,查询慢

4.List和Map,Set的区别

  • 结构特点
    • List和Set是存储单列数据的集合,Map是存储键和值这样的双列数据的集合;List中存储的数据是有顺序,并且允许重复;Map中存储的数据是没有顺序的,其键是不能重复的,它的值可以有重复,Set中存储的数据是无序的,且不允许有重复,但元素在集合中的位置由元素的hashCode决定,位置是固定的(Set集合根据hashcode来进行数据的存储,所以位置是固定的,但是位置不是用户可以控制的,所以队友用户来说set中的元素还是无序的)
  • 实现类
    • List接口有三个实现类(LinkedList:基于链表实现,链表内存是散乱的,每一个元素存储本身内存地址的同时还存储下一个元素的地址.链表增删快,查找慢;ArrayList:基于数组实现,非线程安全的,效率高,便于索引,但不便于插入删除;Voctor:基于数组实现,线程安全的,效率低)
    • Map接口有三个实现类(HashMap:基于hash表的Map接口实现,非线程安全,高效,支持null值和null键;HashTable:线程安全,低效,不支持null值和null键;LinkedHashMap:是HashMap的一个子类,保存了记录的插入顺序;SortMap接口:TreeMap,能够把它保存的记录根据键排序,默认是键值的升序排序)
    • Set接口有两个实现类(HashSet:底层是由HashMap实现,不允许集合中有重复的值,使用该方式时需要重写equals()和hashCode()方法;LinkedHashSet:继承与HashSet,同时又基于LinkedHashMap来进行实现,底层使用的是LinkedHashMap).
  • 区别
    • List集合中对象按照索引位置排序,可以有重复对象,允许按照对象在集合中的索引位置检索对象,例如通过list.get(i)方法来获取集合中的元素;Map中的每一个元素包含一个键和一个值,成对出现,键对象不可以重复,值对像可以重复;Set集合中的对象不按照特定的方式排序,并且没有重复对象,但它的实现类能对集合中的对象按照特定的方式排序,例如TreeSet类,可以按照默认顺序,也可以通过实现比较器接口来自定义排序方式

5.HashMap和HashTable有什么区别?

HashMap是线程不安全的,HashMap是Map的一个子接口,是将键映射到值得对象,不允许键值重复,允许空键和空值;由于非线程安全,HashMap的效率要比HashTable的效率高一些.
HashTable是线程安全的一个集合,不允许null值作为一个key值或者Value值
HashTable是sychronize,多个线程访问时不需要自己为它的方法实现同步,二HashMap在被多个线程访问的时候需要自己为它的方法实现同步

6.数组和链表分别比较适合用于什么场景,为什么?

  • 数组和链表简介
    • 在计算机中要对给定的数据集进行若干处理,首要任务是把数据集的一部分(当数据量非常大时,可能只能一部分一部分地读取数据到内存中来处理)或全部存储到内存中,然后再对内存中的数据进行各种处理.
      例如,对于数据集S{1,2,3,4,5,6},要求S中元素的和,首先要把数据存储到内存中,然后再将内存中的数据相加.
      当内存空间中有足够大的连续空间时,可以把数据连续的存放在内存中,各种编程语言中的数组一般都是按这种方式存储的;当内存中只有一些离散的可用空间时,想连续存储数据就非常困难了,这时能想到的一种解决方式是移动内存中的数据,把离散的空间狙击成连续的一块大空间,这样做当然也可用,单杀这种情况因为可能要移动别人的数据,所以会存在一些困难,移动的过程中也有可能会把一些别人的重要数据给丢失.另外一种,不影响别人的数据存储方式是把数据几种的数据分开离散地存储到这些不连续空间中.这时为了能吧数据几种的所有数据联系起来,需要在前一块数据的存储空间中记录下一块数据的地址,这样只要知道第一块内存空间的地址就能环环相扣地把数据集整体联系在一起了.c/c++中用指针实现的链表就是这种存储形式.
      由上可知,内存中的存储形式可以分为连续存储和离散存储两种.因此,数据的物理存储结构就有连续存储和离散存储两种,他们对应了我们通常所说的数组和链表.
  • 数组和链表的区别
    • 数组是将元素在内存中连续存储的;它的优点:因为数据是连续存储的,内存地址连续,所以在查找数据的时候效率比较高;它的缺点:在存储之前,我们需要申请一块连续的内存空间,并且在编译的时候就必须确定好他的空间的大小.在运行的时候空间的大小是无法随着你的需要进行增加和减少而改变的,当数据量比较大的时候,有可能会出现越界的情况,数据比较小的时候,又有可能会浪费掉内存空间.在改变数据个数时,插入,增加,删除数据效率比较第.
    • 链表是动态申请内存空间,不需要像数组需要提前申请好内存的大小,链表只需在用的时候申请就可以,根据需要来动态申请或者删除内存空间,对于数据增加和删除已经插入比数组灵活.还有就是链表中数据在内存中可以在任意位置,通过应用来关联数据(就是通过存在元素的指针来联系)
  • 链表和数组使用场景
    • 数组应用场景:数据比较少;将会从哪个做的运算是按序号访问数据元素;数组更容易实现,任何高级语言都支持;构建的线性表比较稳定
    • 链表应用场景:对线性表的长度或者规模难以估计;频繁做插入删除操作;构建动态性比较强的线性表

7.Java中ArrayList和LinkedList的区别

ArrayList和Vector使用了数组的实现,可以认为ArrayList或Vector封装了对内部数组的操作,比如向数组中添加,删除,插入新的元素或者数据的扩展和重定向.
LinkedList使用了循环双向链表数据结构.与基于数组的ArrayList相比,这是两种截然不同的实现技术,这也决定了它们将适用于完全不同的工作场景.
LinkedList链表由一系列列表项连接而成.一个表项总是包含3个部分:元素内容,前驱表和后驱表

8.List a=new ArrayList()和ArrayList a = new ArrayList()的区别?

List list = new ArrayList();这句创建了一个ArrayList对象后把他给了List.此时它是一个List对象,有些ArrayList有但是List没有的属性和方法,它就不能再用了.而ArrayList list = new ArrayList();创建的对象保留了ArrayList的所有属性.所以需要用到ArrayList特有的方法的时候不能用前者.如trimToSize()方法是ArrayList特有的

9.面对集合更新操作时,ArrayList和LinkedList哪个更适合?

  • ArrayList是实现了基于动态数组的数据结构,LinkedList是基于链表的数据结构
  • 如果集合数据是对于集合随机访问get和set,ArrayList绝对优于LinkedList,因为LinkedList要移动指针
  • 如果集合数据是对于集合新增和删除操作add和remove,LinkedList比较占优势,因为ArrayList要移动数据
    总体而言:
  • 对ArrayList和LinkedList而言,在队列末尾增加一个元素所花的开销都是固定的.对于ArrayList而言,主要是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;而LinkedList而言,这个开销是统一的
  • 在ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的
  • LinkedList不支持高效的随机元素访问
  • ArrayList的空间浪费主要体现在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的媒体哥元素都要消耗相当的空间
    可以这样说:当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;当你操作是在一列纾解的前面或者中间添加或者删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了

猜你喜欢

转载自blog.csdn.net/Cyy19970527/article/details/81748264