• Java面试-Java容器有哪些


    Java 容器分为 Collection 和 Map 两大类。具体的分类如下:

    Collection

      List(有序,可重复)    

        ArrayList,底层用Object数组实现,特点是查询效率高,增删效率低,线程不安全, 初始化长度是10,默认是16,通过定义更大的数组,将旧数组中的值复制到新数组实现扩容 newC = 1.5oldC +1
        LinkedList,底层使用双向循环链表实现,特点是查询效率低,增删效率高,线程不安全,因为线程不同步
        Vector,底层用长度可以动态增长的对象数组实现,它的相关方法用 Synchronized 进行了线程同步,所以线程安全,效率低
          Stack,栈。特点是:先进后出(FILO, First In Last Out)。继承于Vector
      Set 无序,不可重复
        HashSet,底层用HashMap实现,本质是一个简化版的HashMap,因此查询效率和增删效率都比较高。其add方法就是在map中增加一个键值对,键对象就是这个元素,值对象是PRESENT的对象
          LinkedHashSet,LinkedHashSet继承自HashSet,内部使用的是LinkHashMap。这样做的意义或者好处就是LinkedHashSet中的元素顺序是可以保证的,也就是说遍历序和插入序是一致的。
        TreeSet,底层用TreeMap实现,底层是一种二叉查找树(红黑树),需要对元素做内部排序。内部维持了一个简化版的TreeMap,并通过key来存储Set元素。使用时,要对放入的类实现                                 Comparable接口,且不能放入null

    Map  

    HashMap,采用散列算法来实现,底层用哈希表来存储数据,因此要求键不能重复。线程不安全,HashMap在查找、删除、修改方面效率都非常高。允许key或value为null

                            哈希表:本质是“数组+链表”,源码中Entery[] table是HashMap的核心数组结构,称为“位桶数组”。其中Entery对象时一个单向链表,存储了四部分(hash值,key,value,next)内容。

                早期的hash值总是1,此时,每一个对象都会存储到索引为1的位置,每存储一个都会发生hash冲突,形成了一个非常长的链表,HashMap也就退化成了一个“链表”。

               如果利用相除取余算法,能使hash值均匀地分布在[0,数组长度-1]区间内,早期的HashTable就是采用这种算法,但由于用了除法,所以效率非常低。

                JDK后来改进了算法,首先约定数组的长度必须为2的整数幂,这样可以使用位运算实现取余效果,hash值 = hashcode & (数组长度-1)。而且为了获得更好的散列效果,JDK对                                         hashcode进行了两次散列处理,目标就是为了使分布的更散列,更均匀。

                扩容问题:hashMap 的位桶数组,初始大小为16.负载因子为0.75,每次扩容2倍。需要注意的是,扩容很耗时。因为扩容的本质是定义更大的数组,并将就数组中的内容逐个复制                                                    到新数组中。在JDK8中,HashMap在存储一个元素时,当对应链表长度大于8时,链表就转化为红黑树,这样就大大提高了查询效率

                                   

        LinkedHashMap,HashMap和双向链表合二为一即是LinkedHashMap。所谓LinkedHashMap,其落脚点在HashMap,因此更准确地说,它是一个将所有Entry节点链入一个双向链表的HashMap。虽然LinkedHashMap增加了时间和空间上的开销,但是它通过维护一个额外的双向链表保证了迭代顺序。特别地,该迭代顺序可以是插入顺序,也可以是访问顺序。因此,根据链表中元素的顺序可以将LinkedHashMap分为:保持插入顺序的LinkedHashMap 和 保持访问顺序的LinkedHashMap,其中LinkedHashMap的默认实现是按插入顺序排序的。

      HashTable,与HashMap类似,只是其中的方法添加了synchronized关键字以确保线程同步检查,线程安全,但效率较低。不允许key或value为null
      TreeMap,红黑树的典型实现。TreeMap和HashMap实现了同样的接口Map。在需要Map中Key按照自然排序时才选用TreeMap

      ConcurrentHashMap, 它在JDK1.7和1.8中略有差别

    JDK1.7中:

    由于JDK没有对HashMap做任何的同步操作,所以并发会出问题,甚至出现死循环导致系统不可用。因此 JDK 推出了专项专用的 ConcurrentHashMap ,该类位于 java.util.concurrent 包下,专门用于解决并发问题。和 HashMap 非常类似,唯一的区别就是其中的核心数据如 value ,以及链表都是 volatile 修饰的,保证了获取时的可见性。

    原理上来说:ConcurrentHashMap 采用了分段锁技术,其中 Segment 继承于 ReentrantLock。不会像 HashTable 那样不管是 put 还是 get 操作都需要做同步处理,理论上 ConcurrentHashMap 支持 CurrencyLevel (Segment 数组数量)的线程并发。每当一个线程占用锁访问一个 Segment 时,不会影响到其他的 Segment。

    由于 HashEntry 中的 value 属性是用 volatile 关键词修饰的,保证了内存可见性,所以每次获取时都是最新值。

    ConcurrentHashMap 的 get 方法是非常高效的,因为整个过程都不需要加锁。

    JDK1.8中:

    1.7 已经解决了并发问题,并且能支持 N 个 Segment 这么多次数的并发,但依然存在 HashMap 在 1.7 版本中的问题。

    那就是查询遍历链表效率太低

    其中抛弃了原有的 Segment 分段锁,而采用了 CAS + synchronized 来保证并发安全性。

    其中,CAS是英文单词Compare And Swap的缩写,翻译过来就是比较并替换。

    【CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。从思想上来说,Synchronized属于悲观锁,悲观地认为程序中的并发情况严重,所以严防死守。CAS属于乐观锁,乐观地认为程序中的并发情况不那么严重,所以让线程不断去尝试更新。】

    1.8 在 1.7 的数据结构上做了大的改动,采用红黑树之后可以保证查询效率(O(logn)),甚至取消了 ReentrantLock 改为了 synchronized,这样可以看出在新版的 JDK 中对 synchronized 优化是很到位的。

    更多请参考:https://blog.csdn.net/weixin_44460333/article/details/86770169

    [ 版权声明 ]: 本文所有权归作者本人,文中参考的部分已经做了标记! 商业用途转载请联系作者授权! 非商业用途转载,请标明本文链接及出处!
  • 相关阅读:
    银行类题目
    Java基础-继承-编写一个Java应用程序,设计一个汽车类Vehicle,包含的属性有车轮个数 wheels和车重weight。小车类Car是Vehicle的子类,其中包含的属性有载人数 loader。卡车类Truck是Car类的子类,其中包含的属性有载重量payload。每个 类都有构造方法和输出相关数据的方法。最后,写一个测试类来测试这些类的功 能。
    Java-set集合
    Java——List集合
    java异常处理:建立exception包,建立Bank类,类中有变量double balance表示存款,Bank类的构造方法能增加存款,Bank类中有取款的发方法withDrawal(double dAmount),当取款的数额大于存款时,抛出InsufficientFundsException,取款数额为负数,抛出NagativeFundsException,如new Bank(100),
    java基础-继承:矩形体积类问题
    类的继承和多态性-编写Java应用程序,定义Animal类,此类中有动物的属性:名称 name,腿的数量legs,统计动物的数量 count;方法:设置动物腿数量的方法 void setLegs(),获得腿数量的方法 getLegs(),设置动物名称的方法 setKind(),获得动物名称的方法 getKind(),获得动物数量的方法 getCount()。定义Fish类,是Animal类的子类,
    实验三 类的继承和多态性
    java基础—继承题目:编写一个Animal类,具有属性:种类;具有功能:吃、睡。定义其子类Fish
    java基础,继承类题目:编写一个Java应用程序,该程序包括3个类:Monkey类、People类和主类 E
  • 原文地址:https://www.cnblogs.com/gslgb/p/14521996.html
Copyright © 2020-2023  润新知