• java容器类


    一、  容器类:

    下图摘自《Java编程思想》,很好地展示了整个容器类的结构。

     

     

    由上图可知,容器类库可分为两大类,各自实现了Collection接口和Map接口,下面就常见的类进行一下分类:

    实现Collection接口的容器类

    Collection 
    ├List 
    │├LinkedList 
    │├ArrayList 
    │└Vector 
    │ └Stack 
    ├Set 

    │├TreeSet
    │└HashSet

    └LinkedHashSet 

    ├Queue

    │├LinkedList 

    │├DelayQueue
    │└PriorityQueue

    实现Map接口的容器类

    Map 
    ├HashMap 

    └LinkedHashMap

    ├Hashtable

    ├IdentityHashMap

    ├TreeMap
    └WeakHashMap

    容器类由两个顶层接口自上而下扩展:

    • Collection: 存放独立元素的序列
    • Map:存放key—value类型的键值对元素。

      其中值得注意的是:Collection提供了Iterable()模式,可以获取到Iterator对集合内的元素进行遍历,而Map则需要先得到Collection进而得到Iterator进行遍历。

      其中 接口List、Set、Queue实现了Collection接口,对应的List、Set和Queue又有其具有实现的类。实现了Map接口的主要有HashMap、LinkedHashMap、Hashtable、IdentityHashMap、TreeMap、WeakHashMap。

    二、  实现Collection接口的容器类

      下面就List、Set和Queue下的几种常见容器展开简要的介绍

    2.1  List接口

      两种典型实现:

    • LinkedList:

      底层实现为链表,对于这种实现结构而言,插入和删除操作效率高,而随机访问元素时效率较ArrayList低。

      同时,又由于LinkedList实现了Deque接口,故而它还能提供List接口中没有定义的方法,专门用于操作表头和表尾的元素,可以当做堆栈和队列使用。

    • ArrayList:

    底层实现为数组,此种结构在随机访问和查询时效率高,而在进行插入和删除操作时效率较低。此外,由于其底层实现是数组,故而当数组大小不足需要增加存储空间时,就需要将现有数组中已有的数据复制到新的存储空间中。

    两种弃用的List实现:

    • Vector:

    Vector和ArrayList一样也是通过数组实现的,故而其特性和ArrayList类似(Vector底层数组实现在扩容时是扩展1倍,而ArrayList则扩展50%+1个),其中值得特别注意的一点是Vector是一种线程安全的容器,即在某一时刻只有一个线程能够写Vector,避免在多线程同时写时引起的不一致性,但由于实现同步(synchronized关键字)需要较高的代价,故访问速度较慢。

    • Stack:

    是Vector的一个子类,实现了一个标准的后进先出的栈。(现在实现堆栈的功能一般使用LinkedList)

    2.2 Set接口

    是一种不包含重复元素的Collection,同时Set允许null元素。加入set的元素必须定义equals()方法来确保对象的唯一性。

    几种典型的实现:

    • Hashset:

    利用哈希函数进行了查询效率上的优化,是一种为快速查找而设计的Set,存入其中的元素必须定义hashCode();

    • LinkedHashSet:

    具有Hashset的查询速度,且内部使用链表来维护元素的顺序。元素同样必须定义HashCode()方法

    • TreeSet:

        保持有序的Set(实现了SortedSet接口),底层结构为红黑树,使用它可以从Set中得到有序的序列。元素必须实现Comparable接口

    2.3  Queue接口:

    • PriorityQueue:

        存储在其中的元素该需要实现Comparable接口,即自己完成优先级的定义

    • Deque:

        双向队列,可以在任何一段添加或移除元素。其中LinkedList实现了Deque接口,可实现队列或栈的数据结构。

    三、实现Map接口的容器类

      Map没有继承Collection的接口,其提供了key到value的映射,一个Map中不能包含相同的key,每个key只能映射一个value。

      几种典型的实现:

    • Hashtable:

      线程安全

      任何非空(non-null)的对象都可作为key或者value。

      添加数据使用put(key, value),取出数据使用get(key),这两个基本操作的时间开销为常数。

    通过initial capacity和load factor两个参数调整性能。通常缺省的load factor 0.75较好地实现了时间和空间的均衡。增大load factor可以节省空间但相应的查找时间将增大,这会影响像get和put这样的操作。

    由于key的对象将通过计算其散列函数确定与之对应的value的位置,因此任何作为key的对象必须实现hashcode和equeals方法。

    • HashMap:

    线程不安全

    HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key,但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低

    • IdentityHashMap:

    比较键(和值)时使用引用“==”代替equal。即在 IdentityHashMap 中,当且仅当 (k1==k2) 时,才认为两个键 k1 和 k2 相等

    而在正常 Map 实现(如 HashMap)中,当且仅当满足下列条件时才认为两个键 k1 和 k2 相等:(k1==null ? k2==null : e1.equals(e2)))。

    该类是应用于特定场景下,即当我们必须使用地址相等来判断值相等的场合,以及我们确定只要其地址不相等,则其equals方法的结果也必定不相等的场合。

    一个很好的例子就是线程本地存储中的ThreadLocal类,该类的原理是根据Thread从其内部的Map中获取线程独立的值,那么当我们使用只判断地址相等的IdentityHashMap就会比HashMap要快一些。

    • WeakHashMap:
      WeakHashMap是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收。
    • ConcurrentHashMap

    线程安全的Map,与HashTable不同的,它的线程安全的实现不涉及到同步加锁,它引入了一个“分段锁”的概念,即将一个大的Map拆分成多个”HashTable”(实质上是Segment),当多线程访问容器中不同数据段的数据时,线程间就不存在锁的竞争关系。

    ConcurrentHashMap是由Segment数组和HashEntry数组结构组成。其中Segment是一种可重入锁,HashEntry则用于存储键值对数据。

    Segment的结构和HashMap类似,是一种数组和链表的结构。一个Segment中包含一个HashEntry数组。每个HashEntry是一个链表结构的元素。每个Segment守护着 一个HashEntry中的元素,当要对HashEntry数组的数据进行修改时,必须首先获得与它对应的Segment锁。

    三、怎么选用容器类

      在日常开发中,怎么选用合适的容器类关乎到程序的性能以及正确性等,所以怎么选用合适的容器类很关键。

      首先一点,容器类中存储的都是对象的引用,而非对象本身。出于便利的角度,一般简称对象的引用为对象。正如上面讲到的不同的容器存储的对象类型不同,并且具有的方法也不同,或是在进行相同操作时的效率也存在差异。

      简单来讲,我们将存储的对象分为元素和键值对两种。

      元素一般采用实现Collection接口的容器类存储。又根据元素是否有序(TreeSet),元素是否唯一有所区别(实现Set接口的类),是否要求线程安全(Vector),常进行的操作(ArrayList和LinkedList的选用)等要求进行筛选;

      而键值对则采用实现Map接口的容器类进行存储,又根据是否要求线程安全(ConcurrentHashMap)、是否有必要进行内存的释放(针对内存优化的WeakHashMap)、是否要求有序(TreeMap)、IdentityHashMap(是否可以用==替换equals来提示效率)等要求来进行筛选。

  • 相关阅读:
    认识岗位-带你一起偷窥产品经理的日常
    SpringBoot单元测试踩坑
    Oracle“ORA-38104: 无法更新ON子句中引用的列”解决方式
    SXSSFWorkbook使用补充
    JAVA复制字符串并用指定字符串拼接
    一个简单for循环的时间复杂度
    SXSSFWorkbook的简单使用
    AOP行为日志
    antV G2 为柱状图添加背景颜色
    AntV G2 图表tooltip重命名
  • 原文地址:https://www.cnblogs.com/zhangyingai/p/7087362.html
Copyright © 2020-2023  润新知