java集合 面试题

  1. HashMap 排序题,上机题
    已知一个HashMap<Integer, User>集合,User 有name (String) 和age (int) 属性。请写一个方法实现对HashMap的排序功能,该访法接收HashMap<Integer, User> 为形参,返回类型为HashMap<Integer, User> ,
    要求对HashMap中的User的age倒序进行排序。排序时key=value键值对不得拆散。
    注意:要做出这道题必须对集合的体系结构非常的熟悉。HashMap 本身就是不可排序的,但是该道题偏偏让给HashMap排序,那我们就得想在API中有没有这样的Map结构是有序的,LinkedHashMap, 对的,就是他,他是
    Map结构,也是链表结构,有序的,更可喜的是他是HashMap的子类,我们返回LinkedHashMap <Integer,User>即可,还符合面向接口(父类编程的思想)。
    但凡是对集合的操作,我们应该保持一个原则就是能用JDK中的API就有JDK中的API,比如排序算法我们不应该去用冒泡或者选择,而是首先想到用Collections集合工具类。
    在这里插入图片描述

  2. 请问ArrayList、HashSet、 HashMap 是线程安全的吗?如果不是我想要线程安全的集合怎么办?
    都不是
    在集合中Vector和HashTable 倒是线程安全的。你打开源码会发现其实就是把各自核心方法添加上了synchronized关键字。
    上面几个函数都有对应的返回值类型,传入什么类型返回什么类型。打开源码其实实现原理非常简单,就是将集合的核心方法添加上了synchronized关键字。

  3. ArrayList 内部用什么实现的?
    (回答这样的问题,不要只回答个皮毛,可以再介绍一下ArrayList内部是如何实现数组的增加和删除的,因为数组在创建的时候长度是固定的,那么就有个问题我们往ArrayList中不断的添加对象,它是如何管理这些数组呢? )
    ArrayList内部是用Object[]实现的。接下来我们分别分析ArrayList的构造、add、 remove、 clear 方法的实现原理。
    默认数组长度为10
    一、构造函数
    1)空参构造
    在这里插入图片描述
    array是一个 Object[]类型。当我们new 一个空参构造时系统调用了EmptyArray.OBJECT属性, EmptyArray仅仅是一个系统的类库,该类源码如下:
    在这里插入图片描述也就是说当我们new一个空参ArrayList 的时候,系统内部使用了一个new Object[0]数组。
    2)带参构造1
    在这里插入图片描述在这里插入图片描述
    该构造函数传入一个int值,该值作为数组的长度值。如果该值小于0,则抛出一个运行时异常。如果等于0,则使用一个空数组,如果大于0,则创建一个长度为该值的新数组。
    3)带参构造2
    在这里插入图片描述
    如果调用构造函数的时候传入了一个Collection 的子类,那么先判断该集合是否为null,为null则抛出空指针异常。如果不是则将该集合转换为数组a,然后将该数组赋值为成员变量array,将该数组的长度作为成员变量size.这里面它先判断a.getClass是否等于0bjectl].class,其实一般都是相等的,我也暂时没想明白为什么多加了这个判断,toArray方法是Collection接口定义的,因此其所有的子类都有这样的方法,list集合的toArray和Set集合的toArray返回的都是Object[]数组。
    二、add方法
    add方法有两个重载,这里只研究最简单的那个。
    在这里插入图片描述
    1、首先将成员变量array赋值给局部变量a,将成员变量size赋值给局部变量s。
    2、判断集合的长度s是否等于数组的长度(如果集合的长度已经等于数组的长度了,说明数组已经满了,该重新分配新数组了),重新分配数组的时候需要计算新分配内存的空间大小,如果当前的长度小于MIN_ CAPACITY_ INCREMENT/2 (这个常量值是12,除以2就是6,也就是如果当前集合长度小于6)则分配12个长度,如果集合长度大于6则分配当前长度s的一半长度。这里面用到了三元运算符和位运算, s >> 1,意思就是将s往右移1位,相当于s=s/2,只不过位运算是效率最高的运算。
    3、将新添加的object对象作为数组的a[s]个元素。
    4、修改集合长度size为s+1
    5、modCotun++ ,该变量父类中声明的,用于记录集合修改的次数,记录集合修改的次数是为了防止在用迭代器迭代集合时避免并发修改异常,或者说用于判断是否出现并发修改异常的。
    6、return true,这个返回值意义不大,因为一直返回true,除非报了一个运行时异常。
    三、remove 方法
    remove方法有两个重载,我们只研究remove (int index)方法。
    在这里插入图片描述
    1、 先将成员变量array和size赋值给局部变量a和s。
    2、判断形参index是否大于等于集合的长度,如果成了则抛出运行时异常
    3、获取数组中脚标为index的对象result,该对象作为方法的返回值
    4、调用System的arraycopy函数,拷贝原理如下图所示。
    在这里插入图片描述
    5、接下来就是很重要的一个工作,因为删除了一个元素,而且集合整体向前移动了一位,因此需要将集合最后一个元素设置为null, 否则就可能内存泄露。
    6、重新给成员变量array和size赋值
    7、记录修改次数
    8、返回删除的元素(让用户再看最后一眼)

    四、clear 方法
    在这里插入图片描述如果集合长度不等于0,则将所有数组的值都设置为null,然后将成员变量size设置为0即可,最后让修改记录加1。

  4. 并发集合和普通集合如何区别?
    并发集合常见的有ConcurrentHashMap、ConcurrentLinkedQueue、ConcurrentLinkedDeque等。并发集合位于java.util.concurrent 包下,是jdk1.5 之后才有的
    在java中有普通集合、同步(线程安全) 的集合、并发集合。普通集合通常性能最高,但是不保证多线程的安全性和并发的可靠性。线程安全集合仅仅是给集合添加了synchronized同步锁,严重牺牲了性能,而且对并发的效率就更低了,并发集合则通过复杂的策略不仅保证了多线程的安全又提高的并发时的效率。
    ConcurrentHashMap是线程安全的HashMap的实现,默认构造同样有initialCapacity和loadFactor属性,不过还多了一个concurrencyLevel属性,三属性默认值分别为16、0.75 及16。其内部使用锁分段技术,维持这锁
    Segment的数组,在Segment数组中又存放着Entity[数组,内部hash算法将数据较均匀分布在不同锁中。
    put操作:并没有在此方法上加上synchronized,首先对key.hashcode进行hash操作,得到key的hash值。
    hash操作的算法和map也不同,根据此hash值计算并获取其对应的数组中的Segment对象(继承自ReentrantLock),接着调用此Segment对象的put方法来完成当前操作。

  5. List 的三个子类的特点
    ArrayList底层结构是数组,底层查询快,增删慢。
    LinkedList底层结构是链表型的,增删快,查询慢。
    voctor底层结构是数组 线程安全的,增删慢查询慢。

  6. List 和Map、Set 的区别
    6.1结构特点
    List和Set是存储单列数据的集合,Map是存储键和值这样的双列数据的集合; List 中存储的数据是有顺序,并允许重复; Map 中存储的数据是没有顺序的,其键是不能重复的,它的值是可以有重复的,Set 中存储的数据是无
    序的,且不允许有重复,但元素在集合中的位置由元素的hashcode决定,位置是固定的(Set 集合根据hashcode来进行数据的存储,所以位置是固定的,但是位置不是用户可以控制的,所以对于用户来说set中的元素还是无序的) ;
    6.2实现类
    List接口有三个实现类

    1. LinkedList:基于链表实现,链表内存是散乱的,每一个元素存储本身内存地址的同时还存储下一个元素的地址。链表增删快,查找慢;
    2. ArrayList: 基于数组实现,非线程安全的,效率高,便于索引,但不便于插入删除;
    3. Vector: 基于数组实现,线程安全的,效率低。

    Map接口有三个实现类

    1. HashMap:基于hash表的Map接口实现,非线程安全,高效,支持null值和null键;
    2. HashTable:线程安全,低效,不支持null值和null键; LinkedHashMap: 是HashMap的一个子类,保存了记录的插入顺序;
    3. SortMap 接口: 实现类TreeMap, 能够把它保存的记录根据键排序,默认是键值的升序排序。

    Set接口有两个实现类

    1. HashSet: 底层是由HashMap实现,不允许集合中有重复的值,使用该方式时需要重写equals0和hashCode()方法;
    2. LinkedHashSet: 继承与HashSet,同时又基于LinkedHashMap来进行实现,底层使用的是LinkedHashMp。

    6.3 区别
    List集合中对象按照索引位置排序,可以有重复对象,允许按照对象在集合中的索引位置检索对象,例如通过list.get()方法来获取集合中的元素;
    Map中的每一个元素包含一个键和一个值,成对出现,键对象不可以重复,值对象可以重复;
    Set 集合中的对象不按照特定的方式排序,并且没有重复对象,但它的实现类能对集合中的对象按照特定的方式排序,例如TreeSet类,可以按照默认顺序,也可以通过实现Java.util.Comparator接口来自定义排序
    方式。

  7. HashMap 和HashTable 有什么区别?
    HashMap是线程不安全的,HashMap是将键映射到值得对象,不允许键值重复允许空键和空值:由于非线程安全,HashMap的效率要较HashTable的效率高一些
    HashTable是线程安全的一个集合,不允许null值作为一个key值或者Value值;多个线程访问时不需要自己为它的方法实现同步而HashMap在被多个线程访问的时候需要自己为它的方法实现同步;

  8. 数组和链表分别比较适合用于什么场景,为什么?
    ** 数组和链表的区别**
    数组是将元素在内存中连续存储的;它的优点:因为数据是连续存储的,内存地址连续,所以在查找数据的时候效率较高;它的缺点:在存储之前,我们需要申请一块连续的内存空间,并且在编译的时候就必须确定好它的空间的大小。在运行的时候空间的大小是无法随着你的需要进行增加和减少而改变的,当数据两比较大的时候,有可能会出现越界的情况,数据比较小的时候,又有可能会浪费掉内存空间。在改变数据个数时,增加、插入、删除数据效率比较低
    链表是动态申请内存空间,不需要像数组需要提前申请好内存的大小,链表只需在用的时候申请就可以,根据需要来动态申请或者删除内存空间,对于数据增加和删除以及插入比数组灵活。还有就是链表中数据在内存中可以在任意的位置,通过应用来关联数据(就是通过存在元素的指针来联系)

  9. Java 中ArrayList和Linkedlist区别?
    ArrayList和Vector使用了数组的实现,可以认为ArrayList或者Vector封装了对内部数组的操作,比如向数组中添加,删除,插入新的元素或者数据的扩展和重定向。
    LinkedList使用了循环双向链表数据结构。与基于数组的ArrayList相比,这是两种截然不同的实现技术,这也决定了它们将适用于完全不同的工作场景。
    LinkedList链表由一系列表项连接而成。一个表项总是包含3个部分:元素内容,前驱表和后驱表,如图所示:
    在这里插入图片描述
    在下图展示了一个包含3个元素的LinkedList 的各个表项间的连接关系。在JDK的实现中,无论LikedList否为空,链表内部都有一个header项,它既表示链表的开始,也表示链表的结尾。表项header的后驱表项便是链表中第一个元素, 项header的前驱表项便是链表中最后一个元素。
    在这里插入图片描述

  10. List a=new ArrayList()和ArrayList a =new ArrayList()的区别?
    List list = new ArrayList();这句创建了一个ArrayList的对象后把上溯到了List。此时它是一个List对象了,有些ArrayList有但是List 没有的属性和方法,它就不能再用了。
    ArrayList list =new ArrayList();创建一对象则保留 了ArrayList的所有属性。所以需要用到ArrayList独有的方法的时候不能用前者。实例代码如下:
    在这里插入图片描述

  11. Collection 和Map的集成体系
    在这里插入图片描述在这里插入图片描述

  12. Map中的key和value可以为null么?
    HashMap对象的key. value 值均可为null.
    HahTable对象的key、value 值均不可为null.
    且两者的的key值均不能重复,若添加key相同的键值对,后面的value会自动覆盖前面的value,但不会报错。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值