java面试题29 牛客 以下关于集合类ArrayList、LinkedList、HashMap描述错误的是()

A HashMap实现Map接口,它允许任何类型的键和值对象,并允许将null用作键或值
B ArrayList和LinkedList均实现了List接口
C 添加和删除元素时,ArrayList的表现更佳
D ArrayList的访问速度比LinkedList快

蒙蔽树上蒙蔽果,蒙蔽树下你和我,我们先看看三者之间的一点使用规则

一、LinkedHashMap

LinkedHashMap会将元素串起来,形成一个双链表结构。可以看到,其结构在HashMap结构上增加了链表结构。数据结构为(数组 + 单链表 + 红黑树 + 双链表),图中的标号是结点插入的顺序


在这里插入图片描述
1. 类的继承关系

public class LinkedHashMap<K,V>  extends HashMap<K,V> implements Map<K,V>

LinkedHashMap继承了HashMap,所以HashMap的一些方法或者属性也会被继承;同时也实现了Map结构(HashMap原理分析

2. 类的属性,相比HashMap新增(由于继承HashMap,所以HashMap中的非private方法和字段,都可以在LinkedHashMap直接中访问)

// 链表头结点
transient LinkedHashMap.Entry<K,V> head;// 链表尾结点
transient LinkedHashMap.Entry<K,V> tail;// 访问顺序(可以指定accessOrder的值,从而控制访问顺序)
final boolean accessOrder;

二、ArrayList

在这里插入图片描述

1) 每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向ArrayList中不断添加元素,其容量也自动增长。自动增长会带来数据向新数组的重新拷贝,因此,如果可预知数据量的多少,可在构造ArrayList时指定其容量。在添加大量元素前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量,这可以减少递增式再分配的数量2)    transient Object[] elementData底层的数据结构就是数组,数组元素类型为Object类型,即可以存放所有类型数据。我们对ArrayList类的实例的所有的操作底层都是基于数组的3)ArrayList提供了三种方式的构造器,可以构造一个默认初始容量为10的空列表、构造一个指定初始容量的空列表以及构造一个包含指定collection的元素的列表,这些元素按照该collection的迭代器返回它们的顺序排列的4)java 1.7之前ArrayList默认大小为10,但是1.8之后,默认是空,只有当add第一个元素时,才设置值默认值为105)ArrayList扩容时,正常情况下会扩容1.5倍(newCapacity = oldCapacity + (oldCapacity >> 1),特殊情况下(新扩展数组大小已经达到了最大值)则只取最大值6)indexOf是从头开始查找与指定元素相等的元素,注意,是可以查找null元素的,意味着ArrayList中可以存放null元素的。与此函数对应的lastIndexOf,表示从尾部开始查找7)remove函数用户移除指定下标的元素,此时会把指定下标到数组末尾的元素向前移动一个单位,并且会把数组最后一个元素设置为null,这样是为了方便之后将整个数组不被使用时,会被GC,可以作为小的技巧使用

三、LinkedList

LinkedList底层使用的双向链表结构,有一个头结点和一个尾结点,双向链表意味着我们可以从头开始正向遍历,或者是从尾开始逆向遍历,并且可以针对头部和尾部进行相应的操作
在这里插入图片描述


1. 内部类(内部类Node就是实际的结点,用于存放实际元素的地方)

private static class Node<E> {E item; // 数据域Node<E> next; // 后继Node<E> prev; // 前驱// 构造函数,赋值前驱后继Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;}
}

2. 类的属性

LinkedList的属性非常简单,一个头结点、一个尾结点、一个表示链表中实际元素个数的变量。注意,头结点、尾结点都有transient关键字修饰,这也意味着在序列化时该域是不会序列化的

3. 注意点

1)add函数用于向LinkedList中添加一个元素,并且添加到链表尾部

2)在调用remove移除结点时,会调用到unlink函数,将指定的结点从链表中断开

3)LinkedList可以作为双端队列使用,这也是队列结构在Java中一种实现,当需要使用队列结构时,可以考虑LinkedList

四、HashSet和LinkedHashSet

1. HashSet底层是基于HashMap实现的,LinkedHashSet基于LinkedHashMap实现,所以HashSet、LinkedHashSet数据结构就是HashMap或者LinkedHashMap的数据结构

2. HashSet中由于只包含键,不包含值,由于在底层具体实现时,使用的HashMap或者是LinkedHashMap(可以指定构造函数来确定使用哪种结构),我们知道HashMap是键值对存储,所以为了适应HashMap存储,HashSet增加了一个PRESENT类域(类所有),所有的键都有同一个值(PRESENT)

3. add、contains、remove函数都是基于HashMap或者LinkedHashMap做的操作

4. LinkedHashSet继承自HashSet,也实现了一些接口,LinkedHashSet会调用HashSet的父类构造函数,让其底层实现为LinkedHashMap,这样就很好的实现了LinkedHashSet所需要的功能

一、ArrayList 和 LinkedList:

1、区别:

(1)ArrayList是基于动态数组的数据结构,查询快,增删慢,线程不安全。

LinkedList是基于链表的数据结构,查询慢,增删快。线程不安全。

(2)对ArrayList和LinkedList而言,在列表末尾增加一个元素所花的开销都是固定的。

(3)对ArrayList而言,主要开销是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;而对LinkedList而言,这个开销是统一的,分配一个内部Entry对象。
(4)在ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的。
(5)LinkedList不支持高效的随机元素访问。
(6)ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间。

2、ArrayList和LinkedList的时间复杂度:

(1)ArrayList 是线性表:
get() 直接读取第几个下标,复杂度 O(1);
add(E) 添加元素,直接在后面添加,复杂度O(1);
add(index, E) 添加元素,在第几个元素后面插入,后面的元素需要向后移动,复杂度O(n);
remove()删除元素,后面的元素需要逐个移动,复杂度O(n)。
(2)LinkedList 是链表的操作:
get() 获取第几个元素,依次遍历,复杂度O(n);
add(E) 添加到末尾,复杂度O(1);
add(index, E) 添加第几个元素后,需要先查找到第几个元素,直接指针指向操作,复杂度O(n);
remove()删除元素,直接指针指向操作,复杂度O(1)。

3、ArrayList为什么是线程不安全的?

(1)在 Items[Size] 的位置存放此元素;
(2)增大 Size 的值:
①在单线程运行的情况下,如果 Size = 0,添加一个元素后,此元素在位置 0,而且 Size=1;
②而如果是在多线程情况下,比如有两个线程,线程 A 先将元素存放在位置 0。但是此时 CPU 调度线程A暂停,线程 B 得到运行的机会。线程B也向此 ArrayList 添加元素,因为此时 Size 仍然等于 0 (注意哦,我们假设的是添加一个元素是要两个步骤哦,而线程A仅仅完成了步骤1),所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增加 Size 的值。 那好,现在我们来看看 ArrayList 的情况,元素实际上只有一个,存放在位置 0,而 Size 却等于 2。这就是“线程不安全”了。

4、ArrayList能否无限添加元素?会抛异常吗?

使用ArrayList时,可以无限的往里添加元素,因为它底层是由数组实现的,使用无参构造方法时系统会默认提供默认参数10,而使用有参构造函数时我们会指定大小,当我们添加的元素个数大于数组的初始化长度时,ArrayList会自动为其扩容,扩容后的大小是int newCapacity = (oldCapacity * 3)/2 + 1;  (自动增加原来的50%)

HashMap介绍:

(1)HashMap是基于Map接口的非同步实现,结构可以看成数组+链表。

HashMap 是一个散列表,它存储的内容是键值对映射,每一个键值对也叫做Entry(Entry的组成:Key、value、next),key和value都可以为null。HashMap中的映射不是有序的。

(2)HashMap 的实现不是同步的,这意味着它不是线程安全的,后执行的线程会覆盖先执行线程的修改,在多线程环境下若使用HashMap需要使用Collections.synchronizedMap()方法来获取一个线程安全的集合。

Collections.synchronizedMap()实现原理是:Collections定义了一个SynchronizedMap的内部类,这个类实现了Map接口,在调用方法时使用synchronized来保证线程同步,当然了实际上操作的还是我们传入的HashMap实例,简单的说就是Collections.synchronizedMap()方法帮我们在操作HashMap时自动添加了synchronized来实现线程同步。

(3)HashMap 的实例有两个参数影响其性能:“初始容量” 和 “加载因子”。

容量是哈希表中桶的数量,初始容量只是哈希表在创建时的容量,容量必须是2的N次幂,这是为了提高计算机的执行效率。加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 resize 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。(创建新表,将旧表映射到新表中)

通常,默认加载因子是 0.75, 这是在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 resize 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 resize 操作。

(4)JDK8中HashMap的新特性:如果某个桶中的链表记录过大的话(当前是TREEIFY_THRESHOLD = 8),就会把这个链动态变成红黑二叉树,使查询最差复杂度由O(N)变成了O(logN)。

3、一些有关HashMap的问题:

(1)HashMap的get()、put()方法的工作原理?

我们通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,让后找到bucket位置来储存Entry对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。

(2)为什么String, Interger这样的wrapper类适合作为HashMap键?

因为String是不可变的,也是final的,而且已经重写了equals()和hashCode()方法了。其他的wrapper类也有这个特点。不可变性是必要的,因为为了要计算hashCode(),就要防止键值改变,如果键值在放入时和获取时返回不同的hashcode的话,那么就不能从HashMap中找到你想要的对象。不可变性还有其他的优点如线程安全。如果你可以仅仅通过将某个field声明成final就能保证hashCode是不变的,那么请这么做吧。因为获取对象的时候要用到equals()和hashCode()方法,那么键对象正确的重写这两个方法是非常重要的。如果两个不相等的对象返回不同的hashcode的话,那么碰撞的几率就会小些,这样就能提高HashMap的性能。
正确答案: C

我是歌谣,有什么不合理之处欢迎指出。喜欢敲代码,偶尔刷刷题。

阅读目录(置顶)(长期更新计算机领域知识)

阅读目录(置顶)(长期更新计算机领域知识)

阅读目录(置顶)(长期科技领域知识)

歌谣带你看java面试题

java面试题29 牛客 以下关于集合类ArrayList、LinkedList、HashMap描述相关推荐

  1. java面试题28 牛客 下面有关java classloader说法错误的是?

    java面试题28 牛客 下面有关java classloader说法错误的是? A Java默认提供的三个ClassLoader是BootStrap ClassLoader,Extension Cl ...

  2. java面试题23 牛客ArrayLists和LinkedList的区别,下述说法正确的有?

    java面试题23 牛客ArrayLists和LinkedList的区别,下述说法正确的有? A ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构. B 对于随 ...

  3. Java面试题 22 牛客 Java是一门支持反射的语言,基于反射为Java提供了丰富的动态性支持

    Java面试题 22 牛客 Java是一门支持反射的语言,基于反射为Java提供了丰富的动态性支持,下面关于Java反射的描述,哪些是错误的:(          ) A Java反射主要涉及的类如C ...

  4. Java面试题18 牛客 假定Base b = new Derived();

    Java面试题18 牛客 假定Base b = new Derived(); 调用执行b.methodOne()后,输出结果是什么? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ...

  5. Java面试题17 牛客 下面哪个选项正确创建socket连接?

    Java面试题17 牛客 下面哪个选项正确创建socket连接? Socket s = new Socket(8080); Socket s = new Socket("192.168.1. ...

  6. Java面试题16 牛客 以下java程序代码,执行后的结果是()

    Java面试题16 牛客 以下java程序代码,执行后的结果是() 1 2 3 4 5 6 7 8 9 10 public class Test {     public static void ma ...

  7. Java面试题15牛客 以下关于Integer与int的区别错误的是

    Java面试题15牛客 以下关于Integer与int的区别错误的是 A int是java提供的8种原始数据类型之一 B Integer是java为int提供的封装类 C int的默认值为0 D In ...

  8. Java面试题19 牛客下面有关java的引用类型,说法正确的有?

    Java面试题19下面有关java的引用类型,说法正确的有? A:对于一个对象来说,只要有强引用的存在,它就会一直存在于内存中 B:如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可 ...

  9. java面试题11 牛客:如下语句通过算术运算和逻辑运算之后i和 j的结果是

    如下语句通过算术运算和逻辑运算之后i和 j的结果是( ) 1 2 3 4 5 6 int i=0; int j=0; if((++i>0)||(++j>0)) { //打印出i和j的值. ...

最新文章

  1. ORACLE新建表空间
  2. CG-CTF-Web-伪装者
  3. HTML5的非主体结构元素(header、footer、hgroup、assress)
  4. linux脚本 sed,Linux脚本利器sed
  5. PlaceHolder和Panel的区别【搜藏】
  6. photon mapping学习笔记
  7. 计算机辅助设计源程序,计算机辅助设计(插值法程序).doc
  8. 世界你好! 个人网站搭建过程
  9. 使用高速通道加速iOS版本审核
  10. 算法荐书(程序员练功+大众科普)
  11. win10 系统无法远程桌面连接到服务器,Win10系统不能建立远程桌面连接总是连接不上如何解决...
  12. 关于产品的一些思考——八千里科技之谁叫我起床
  13. prometheus 告警配置以及配置项解释
  14. 试图加载格式不正确的程序 解决方法
  15. 如何关闭WPS烦人的广告推送
  16. 阿里云 实人认证(详细)RPMin
  17. 29-高级路由:BGP清除
  18. 巴士(DFS迭代加深 + 剪枝)
  19. 模型微调(finetune)
  20. operate mow 3.15

热门文章

  1. hdu1466(dp)
  2. 微信支付(APP)集成时碰到的问题(.net提示“无权限”、iOS跳转到微信支付页面中间只有一个“确定”按钮)...
  3. spring ioc原理
  4. [转]根据时间(NSDate)获取具体的信息:月份、星期、天等
  5. uboot中的mmc命令
  6. python android 库_Python库
  7. python能print中文吗_python怎么print汉字
  8. html 转换为cshtml,使用Html而不是csHtml
  9. 计算机设备行业特征,自动装配机在自动化设备行业具有的特点
  10. MSP432 库函数实现 PID 电机调角度、调速