打卡面试题-day05(javaSE)

集合的安全性问题

ArrayList和LinkedList有什么区别
  1. 数据结构不同
    ArrayList是基于数组实现的,LinkedList是基于双向链表实现的。
    LinkedList类不就是List接口的实现类,可以根据索引来随机访问集合中的元素,除此之外,LinkedList还实现了Deque接口,Deque接口是Queue接口的子接口,它代表了一个双向队列。因此LinkedList可以作为双向队列,栈和List集合使用,功能强大。
  2. 因为Array是基于索引的数据结构,所以在数组中所搜和读取数据很快,可以直接返回数组中的index位置的元素,因此在随机访问集合元素上有较好的性能,Array获取数据的时间复杂度为O(1),但是插入和删除效率不高。
  3. LinkedList查询效率低,插入和删除块,查询数据时间复杂度是O(n),但是在插入和删除的时间复杂度为O(1).
  4. LinkedList需要更多的内存,因为ArrayList的每个索引的位置是实际的数据,而LinkedList中的每个节点中存储的是实际数据和前后节点的位置。
HashMap的实现原理

HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元,每一个Entry包含一个key-value键值对,Entry是HashMap中的一个静态内部类。
简单来说,HashMap有数组加链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么查找,添加等操作很快,仅需要一次寻址即可;如果定位到的数组包含链表,对于添加操作,那么复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。
HashMap有4个构造器,其它构造器如果用户没有传入initialCapacity和loadFactor这两个参数,会使用默认值,inittialCapacity默认为16,loadFactor默认为0.75
当发生哈希冲突并且size大于阈值的时候,需要进行数组扩容,扩容时,需要新建一个长度为之前数组2倍的新的数组,然后将当前的Entry数组中的元素全部传输过去,扩容后的新数组长度为之前的2倍,所以扩容相对来说是个耗资源的操作。

jdk1.8中HashMap的性能优化

如果一个数组上的数据链过多,就会导致其性能下降,
jdk1.8在jdk1.7的基础上增加了红黑树来对其进行优化,当链表超过超过8时,链表就转为红黑树,使用红黑树快速增删改查的特点提高HashMap的性能,其中会用到红黑树的插入,,删除,查找等算法。

HashMap有时候会死循环,原因是什么

jdk1.8中hashmap采用的位桶+链表/红黑树的方式,当某个桶的链表的长度超过8的时候,这个链表就会转换成红黑树。
HashMap不会因多线程put导致死循环(jdk1.8用head和tail来保证链表的顺序和之前一样;jdk1.7rehash会导致链表元素),但是还会有数据丢失等弊端(兵法本身的问题)。因此多线程情况下还是建议使用ConcurrentHashMap.
为什么线程不安全
HashMap在并发时可能出现的问题主要是两方面:

  1. 如果多核线程同时使用put方法添加元素,而且假设正好存在两个put和key发生了碰撞(根据hash值计算的bucket一样),那么根据HashMap的实现,这两个key会添加到数组的同一个位置,这样最终会发生其中一个县城put的数据被覆盖。
  2. 如果多个线程同时检测到元素个数超过数组大小*loadFactor,这样就会发生多个线程同时对Node数组进行扩容,都在重新计算元素位置以及复制数据,但是最终只有一个线程扩容后的数组会赋给table,也就是说其他线程的都会丢失,并且各自线程put的数据也丢失。
List的三个子类的特点

ArrayList底层是数组,查询快,增删慢
LinkedList底层是链表(红黑树)增删快,查询慢
Vector底层是数组,线程安全,增删慢,查询也慢

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

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

数组和链表的区别

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

链表和数组使用场景

数组应用场景:数据比较少,经常做的运算是按序号访问数据元素;数组更容易实现,任意高级语言都支持;构建的线性表较稳定。
链表应用场景:对线性表的长度或者规模难以估计;频繁做插入删除操作;构建动态性比较强的线性表。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

double_lifly

点喜欢就是最好的打赏!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值