zoukankan      html  css  js  c++  java
  • JDK的弃儿:Vector、Stack、Hashtable、Enumeration

    随着JDK的发展,一些设计缺陷或者性能不足的类库难免会被淘汰,最常见的就是Vector、Stack、HashTable和Enumeration了。

    Vector(@since 1.0)

    首先看看Vector的UML类图,可以看出,他是一个与ArrayList有着相同继承体系的类,大致功能也和ArrayList一样。Vector与ArrayList最大的不同点在于它是线程安全的,因为其内部几乎所有方法都用了synchronized来修饰。但是,Synchronized是重量级锁,读写操作也没有做适当的并发优化,已经被并发性更好的CopyOnWriteArrayList取代了。所以,当不要求线程安全时,自然会选择ArrayList,如果要求线程安全,往往也会选择CopyOnWriteArrayList或者Collections.synchronizedList()。

    Stack(@since 1.0)

    Stack是Vector的子类,其内部的方法也都是通过无脑加synchronized来实现的,所以虽然线程安全,但是并发性不高。当不要求线程安全时,会选择LinkedList或者ArrayList(LinkedList的API更接近栈的操作,所以最佳选择是LinkedList),当要求线程安全时,我们会用java.util.concurrent包下的某些类。
    再多句嘴,虽然LinkedList的API比较接近栈的操作,但是暴露了许多用不着的方法,这会带来危险。解决方法是编写一个LinkedList的包装类,只暴露与栈相关的方法。

     1 **
     2  * 包装{@code LinkedList},使其仅暴露与栈相关的方法
     3  */
     4 public class Stack<T> {
     5     private LinkedList<T> list;
     6     public Stack() {
     7         list = new LinkedList<>();
     8     }
     9     public void push(T item) {
    10         list.push(item);
    11     }
    12     public T pop() {
    13         return list.pop();
    14     }
    15     public T peek() {
    16         return list.peek();
    17     }
    18     public boolean isEmpty() {
    19         return list.isEmpty();
    20     }
    21     @Override
    22     public String toString() {
    23         return list.toString();
    24     }
    25 }

    Hashtable(@since JDK1.0)

    首先看看Hashtable的UML类图,关键点是其实现了Map接口,所以它是一个存储键值对的容器。通过查看源码,我们知道,其是一个线程安全的类,而且还是用synchronized来实现的,所以并发性不高。所以,当面对不要求线程安全的应用场景时我们会用HashMap代替,要求线程安全的应用场景我们往往也会用ConcurrentHashMap或者Collections.synchronizedMap()来代替。
     
    再再多句嘴,它与HashMap还有一个比较出名的不同点,就是它的散列表实现算法是用线性探测法实现的,该算法要求key不能为null,不然删除键值对时会出问题。另外还要求value不能为null。具体见源码。

     1 public synchronized V put(K key, V value) {
     2     // Make sure the value is not null
     3     if (value == null) { //value不能为null
     4         throw new NullPointerException();
     5     }
     6     // Makes sure the key is not already in the hashtable.
     7     Entry<?,?> tab[] = table;
     8     int hash = key.hashCode(); //key不可以为null
     9     int index = (hash & 0x7FFFFFFF) % tab.length;
    10     @SuppressWarnings("unchecked")
    11     Entry<K,V> entry = (Entry<K,V>)tab[index];
    12     for(; entry != null ; entry = entry.next) {
    13         if ((entry.hash == hash) && entry.key.equals(key)) {
    14             V old = entry.value;
    15             entry.value = value;
    16             return old;
    17         }
    18     }
    19     addEntry(hash, key, value, index);
    20     return null;
    21 }
    22 public synchronized boolean contains(Object value) {
    23     if (value == null) {
    24         throw new NullPointerException();//value不能为null
    25     }
    26     Entry<?,?> tab[] = table;
    27     for (int i = tab.length ; i-- > 0 ;) {
    28         for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) {
    29             if (e.value.equals(value)) {
    30                 return true;
    31             }
    32         }
    33     }
    34     return false;
    35 }

    Enumeration(@since JDK1.0)

    Enumeration是否是JDK的“弃儿”其实是有争论的,有人认为,有了Iterator的存在,Enumeration存在的意义就仅仅是兼容老API(比如Vector、Hashtable)了;又有人认为,Enumeration提供了比Iterator更明确的语义(明确不希望对象被执行移除操作)。

    1     * NOTE: The functionality of this interface is duplicated by the Iterator
    2     * interface.  In addition, Iterator adds an optional remove operation, and
    3     * has shorter method names.  New implementations should consider using
    4     * Iterator in preference to Enumeration.
    5     这个接口的功能与Iterator接口重复了。此外,Iteraotr还有一个可选的remove()方法和更短的名字,新应用应该优先考虑Iterator。

    总之,根据API的说明,我们得知,新应用应优先考虑Iterator接口。
    再再再多句嘴,万一要面对Enumeration,又想有个关于迭代的统一接口,可以使用适配器模式来处理Enumeration。

     1 ** 
     2  * 把Enumeration接口转换成Iterator接口的适配器  
     3  * 适配器模式中的角色 - adaptor 
     4  */  
     5 public class EnumerationIterator<E> implements Iterator<E> {  
     6     /** 
     7      * 被适配的接口 
     8      * 适配器模式中的角色 - adaptee  
     9      */  
    10     private Enumeration<E> enums;  
    11     public EnumerationIterator(Enumeration<E> enums) {  
    12         this.enums = enums;  
    13     }  
    14     @Override  
    15     public boolean hasNext() {  
    16         return enums.hasMoreElements();  
    17     }  
    18     @Override  
    19     public E next() {  
    20         return enums.nextElement();  
    21     }  
    22     /** 
    23      * 因为Enumeration接口不支持remove操作,所以这里简单地抛出异常 
    24      */  
    25     @Override  
    26     public void remove() {  
    27         throw new UnsupportedOperationException();  
    28     }  
    29 }

    总结

    Vector、Stack、Hashtable由于其自身的设计不足而且又有替代的工具,所以在新项目中已难寻其踪。Iterator的强大功能也使Enumeration处境尴尬,也已经很少见到了。

    引用

    1.http://blog.csdn.net/tounaobun/article/details/8581429
    2.https://www.zhihu.com/question/42961567?sort=created

  • 相关阅读:
    b_jd_水坑数量(向外流dfs)
    b_wy_购买商品使得满减最省(01背包)
    b_wy_最优路径(构造树+dfs)
    Redis:List列表相关指令
    Redis:String字符串常用指令
    Redis:linux基本的指令
    Redis:redis-benchmark性能测试/压力测试
    Redis:增大并发量的演进过程
    Kafka的下载安装和测试,及消费端数据中文乱码问题
    Git:常用命令
  • 原文地址:https://www.cnblogs.com/fudashi/p/7214609.html
Copyright © 2011-2022 走看看