• java 容器


    如上图:java完整容器的结构图

    个人觉得java的容器结构是比较复杂的,想弄懂Java的容器,那么这个图会有很大的帮助!

    图中短虚线部分为接口,长虚线部分为抽象类,实线部分为实现类,其中实线加粗为常用类。

    Java SE5以后的版本新增了一些容器,主要是针对于多线程机制的

    值得注意的是Java SE5之后新增了Queue接口继承于Collection,以及实现PriorityQueue和各种风格的BlockingQueue。

    做为容器家族的长老级人物,个人觉得研究一下Collection还是有必要的,下面是Collection中的方法摘要,其中包括继承自Object的方法(注:Collection并没有显示的继承于Object,而继承于Iterable,同时Iterable也非继承于Object,网上有说自动继承于Object,同时给出了 权威的出处,一时间找不到了)

    方法摘要
     boolean add(E e)
              确保此 collection 包含指定的元素(可选操作)。
     boolean addAll(Collection<? extends E> c)
              将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。
     void clear()
              移除此 collection 中的所有元素(可选操作)。
     boolean contains(Object o)
              如果此 collection 包含指定的元素,则返回 true。
     boolean containsAll(Collection<?> c)
              如果此 collection 包含指定 collection 中的所有元素,则返回 true。
     boolean equals(Object o)
              比较此 collection 与指定对象是否相等。
     int hashCode()
              返回此 collection 的哈希码值。
     boolean isEmpty()
              如果此 collection 不包含元素,则返回 true。
     Iterator<E> iterator()
              返回在此 collection 的元素上进行迭代的迭代器。
     boolean remove(Object o)
              从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。
     boolean removeAll(Collection<?> c)
              移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。
     boolean retainAll(Collection<?> c)
              仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。
     int size()
              返回此 collection 中的元素数。
     Object[] toArray()
              返回包含此 collection 中所有元素的数组。
    <T> T[] toArray(T[] a)
              返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。  
          值得注意的是,其实不包括访问元素的get()方法,主要是因为Collection包括Set,而Set是自己维护内部顺序的(这使得随机访问是没有意义的)。因此,如果想检查Collection中的元素,那就必须使用迭代器。

          提到迭代器让我想起了一个问题,如上文的addAll方法,继承于Collection的容器可以将另一种继承于Collection的容器向上转型,然后通过迭代器来遍历,添加到该容器,这是一种适配器的设计模式。这样就方便了不同Collection子集的数据传递。

         看看这个标题又想起一个问题,面试的时候经常为问到Collection与Collections的区别,大三来IBM实习的时候就被问到了,其实很简单,Collection我就不说了,Collections就类似于Arrays,是容器的一个工具类。

    Map是Java容器的又一长老,映射表(也称为关联数组),基本思想是维护一对键-值对,通过键来查找值。

    标准Java类库中包含Map的几种基本实现,包括:HashMap,TreeMap,LinkedHashMap,WeakHashMap,ConcurrentHashMap,IdentityHashMap,他们之间各自有一个自己的特性。

    1. HashMap:HashMap采用特殊的形式进行存储,这种形式被称为散列码,通过HashMap的实现可以看出,HashMap保存了一个数组,在插入数据的时候,同一个Key可以有一个固定的HashCode,通过这个HashCode将<K,V>这样的键值对映射到数组对应的位置,当然在采用这种散列码映射的时候难免会产生冲突,所以数组的每一个位置相当于指向了一个链表,当多个Key映射到同一个hashCode的时候,就要通过equals和==来比较key,所以这样在查找时的效率是相当快的。可以通过构造器设置容量和负载因子,以调整容器的性能。从迭代方法上来说,HashMap有两种迭代方式,一种是根据HashMap内部的HashIterator进行迭代,也就是对HashMap.Entry进行迭代;而另一种方法HashMap提供了一个KeySet功能,让使用者可以通过遍历Key来进行迭代。
    2. LinkedHashMap:类似于HashMap,但是迭代便利他时,取得“键值对”的顺序是插入次序,或者是最近最少使用(LRU)次序。只比HashMap慢一点;而在迭代访问时HashMap相当于是对数组的遍历,而LinkedHashMap是对一个链表的遍历,因为它使用链表来维护内部次序。从内部结构来说LinkedHashMap继承于HashMap又重新实现了自己的Entry和Iterator,这样就具有了上面的功能。
    3. TreeMap:基于AVL Tree(也叫平衡树或者红黑树)的实现。查看“键”或“键值对”时,他们会被排序(次序由Comparable或Comparator决定)。TreeMap的特点在于,所得到的结果是经过排序的。TreeMap是唯一的带有subMap()方法的Map,它可以返回一个子树。
    4. WeakHashMap, 弱键(weak key)映射,允许释放映射所指的对象;这是为解决某类特殊问题而设计的。如果映射之外没有引用指向某个“键”,则此“键”可被垃圾回收器回收。
    5. ConcurrentHashMap,一种线程安全的Map,他不涉及同步加锁。
    6. IdentityHashMap,使用==代替equals对“键”进行比较的散列映射。

    Set,大概看了一些Set的实现类,如HashSet,TreeSet,发现Set其实是基于Map来搭建的,如果你了解了Map的结构那你就知道Set是怎么回事儿了,看了jdk的源码就会知道,原来所谓的Set都是由Map构成的,只不过Map是通过<Key,Value>的形式存储,而Set中的Value都指向同一个对象,jdk中给他起名叫PRESENT(替代者),这样就不会造成太大的空间浪费了。

    HashSet的实现

    1. public class HashSet<E>  
    2.     extends AbstractSet<E>  
    3.     implements Set<E>, Cloneable, java.io.Serializable  
    4. {  
    5.     static final long serialVersionUID = -5024744406713321676L;  
    6.   
    7.     private transient HashMap<E,Object> map; //内部结构的维护使用的HashMap  
    8.   
    9.     // Dummy value to associate with an Object in the backing Map  
    10.     private static final Object PRESENT = new Object();  
    11.   
    12.     /** 
    13.      * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has 
    14.      * default initial capacity (16) and load factor (0.75). 
    15.      */  
    16.     public HashSet() {  
    17.     map = new HashMap<E,Object>();  
    18.     }……  

    而LinkedHashSet继承自HashSet,

    再看一下TreeSet

     
    1. public class TreeSet<E> extends AbstractSet<E>  
    2.     implements NavigableSet<E>, Cloneable, java.io.Serializable  
    3. {  
    4.     /** 
    5.      * The backing map. 
    6.      */  
    7.     private transient NavigableMap<E,Object> m;  
    8.   
    9.     // Dummy value to associate with an Object in the backing Map  
    10.     private static final Object PRESENT = new Object();  
    11.   
    12.     /** 
    13.      * Constructs a set backed by the specified navigable map. 
    14.      */  
    15.     TreeSet(NavigableMap<E,Object> m) {  
    16.         this.m = m;  
    17.     }  

    List和存储顺序

    从List接口展开的实现类有ArrayList,LinkedList,Vector和Stack,其中Vector和Stack被称为遗留类,是用于支持遗留代码,向前兼容,你不应该再去使用这样的东西,但Vector在处理并发的时候加了同步,而ArrayList没有这个功能,以前因为同步的问题总觉得ArrayList并不能完全的替代Vector,但后来才知道Jdk早就提供了一个CopyOnWriteArrayList,专门用于处理并发,所以Vector确实不应该再用了。

    关于ArrayList:ArrayList底层是由数组来实现的,默认会初始化一个初度为10的Object数组,随着数据的增加,创建一个新的数组然后将就数据拷贝过来,长度变换规律如下:

    1. public void ensureCapacity(int minCapacity) {   
    2.     modCount++;   
    3.     int oldCapacity = elementData.length;   
    4.     if (minCapacity > oldCapacity) {   
    5.         int newCapacity = (oldCapacity * 3)/2 + 1;   
    6.         if (newCapacity < minCapacity)   
    7.             newCapacity = minCapacity; // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity);   
    8.         }   
    9.     }  
    10. }  



    新的容量=(旧容量×3)/2+1;有兴趣也可以看一下Vector的实现。

    关于LinkedList:LisnedList底层采用双向链表的链式结构,学过数据结构的都知道,这样的链式结构相对于ArrayList来说优点是插入删除快,缺点是搜索相对较慢。

  • 相关阅读:
    归并排序java实现
    linux中压缩与备份命令总结
    Debug查看Struts2中ExceptionMappingInterceptor拦截器怎么把ExceptionHolder放入值栈中,以及理解拦截器的工作原理。。。
    Linux文件与目录管理命令小结
    (转)常用的正则表达式
    Neither BindingResult nor plain target obiect available as request attribute
    sping mvc访问.js,.css,.img等静态文件
    spring security学习(二)
    初始spring security(一)
    在myeclipse中使用maven前常见错误及解决办法
  • 原文地址:https://www.cnblogs.com/cooking/p/4915167.html
Copyright © 2020-2023  润新知