IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java集合(七)Hashtable使用及源码分析 -> 正文阅读

[Java知识库]Java集合(七)Hashtable使用及源码分析

????Java集合(一)集合框架使用综述
????Java集合(二)ArrayList使用及源码分析
????Java集合(三)LinkedList使用及源码分析
????Java集合(四)Vector源码使用及源码分析
????Java集合(五)Stack使用及源码分析
????Java集合(六)HashMap使用及源码分析
????Java集合(七)Hashtable使用及源码分析

一、Hashtable概述

??HashMap是jdk中最常用的哈希表实现,使用数组加链表的结构来组织数据,不过HashMap是线程不安全的。因此,Hashtable作为线程安全的Map实现诞生了。其继承关系:

public class Hashtable<K,V>
    extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable

??HashMap和HashTabel用法几乎一样,底层实现也几乎一样,但是HashTable的方法添加了synchronized关键字以确保线程安全,但同时也导致效率较低。两者的区别:

  • 1、 hashmap中key和value均可以为null,但是hashtable中key和value均不能为null
  • 2、 hashmap采用的是数组(桶位)+链表+红黑树结构实现,而hashtable中采用的是数组(桶位)+链表实现。
  • 3、 hashmap中出现hash冲突时,如果链表节点数小于8时是将新元素加入到链表的末尾,而hashtable中出现hash冲突时采用的是将新元素加入到链表的开头。
  • 4、 hashmap中数组容量的大小要求是2的n次方,如果初始化时不符合要求会进行调整,而hashtable中数组容量的大小可以为任意正整数。
  • 5、 hashmap中的寻址方法采用的是位运算按位与,而hashtable中寻址方式采用的是求余数。
  • 6、 hashmap不是线程安全的,而hashtable是线程安全的,hashtable中的get和put方法均采用了synchronized关键字进行了方法同步。
  • 7、 hashmap中默认容量的大小是16,而hashtable中默认数组容量是11。

二、Hashtable使用

2.1 构造方法

1、构造一个新的,空的散列表,默认初始容量(11)和负载因子(0.75)。
??public Hashtable()
2、构造一个新的,空的哈希表,具有指定的初始容量和默认负载因子(0.75)。
??public Hashtable(int initialCapacity)
3、构造一个新的,空的哈希表,具有指定的初始容量和指定的负载因子。
??public Hashtable(int initialCapacity, float loadFactor)
4、构造一个与给定地图相同的映射的新哈希表。
??public Hashtable(Map<? extends K, ? extends V> t)

??使用示例:

        Hashtable<String, String> hashtable = new Hashtable<>();
        Hashtable<String, String> hashtable2 = new Hashtable<>(18);
        Hashtable<String, String> hashtable3 = new Hashtable<>(18,0.5f);
        HashMap<String, String> hashMap = new HashMap<>();
        Hashtable<String, String> hashtable4 = new Hashtable<>(hashMap);

2.2 clear

清空Hashtable
??public synchronized void clear()

??使用示例:

        Hashtable<String, String> hashtable = new Hashtable<>();
        hashtable.clear();

2.3 clone

创建这个散列表的浅拷贝
??public synchronized Object clone()

??使用示例:

        Hashtable<String, String> hashtable = new Hashtable<>();
        Hashtable<String, String> hashtable2 = (Hashtable<String, String>) hashtable.clone();

2.4 compute

如果在Hashtable的compute()中传递的重映射函数返回null作为返回值,则该映射将从Hashtable中删除(如果最初不存在,则保持不存在)。
??public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)

??使用示例:

        Map<String, Integer> table = new Hashtable<>(); 
        table.put("Pen", 10); 
        System.out.println("hashTable: " + table.toString());   //hashTable: {Pen=10}

        table.compute("Pen", (key, val)  -> val + 15); 
        System.out.println("new hashTable: " + table);   //new hashTable: {Pen=25}

2.5 computeIfAbsent

如果指定的键尚未与某个值相关联(或映射到 null ),则尝试使用给定的映射函数计算其值,并将其输入到此映射中,除非 null 。
??public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)

??使用示例:

        Map<String, Integer> table = new Hashtable<>(); 
        table.put("Pen", 10); 
        table.put("Book", 500); 
        table.put("Clothes", 400); 
        table.put("Mobile", 5000); 
  
        //hashTable: {Book=500, Mobile=5000, Pen=10, Clothes=400}
        System.out.println("hashTable: " + table.toString()); 
  
        table.computeIfAbsent("newPen", k -> 600); 
        table.computeIfAbsent("newBook", k -> 800); 
  
        //new hashTable: {newPen=600, Book=500, newBook=800, Mobile=5000, Pen=10, Clothes=400}
        System.out.println("new hashTable: " + table); 

2.6 computeIfPresent

如果指定的密钥的值存在且非空,则尝试计算给定密钥及其当前映射值的新映射。
??public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)

??使用示例:

        Hashtable<String, Integer> wordCount = new Hashtable<>();
        wordCount.put("Yiidian", 1);
        wordCount.put("for", 2);
        wordCount.put("Java", 3);
        System.out.println(wordCount); //{Java=3, for=2, Yiidian=1}

        wordCount.computeIfPresent("Yiidian",(key, val) -> val + 100);
        System.out.println( wordCount); //{Java=3, for=2, Yiidian=101}

2.7 contains/containsKey/containsValue

1、是否包含某个Value
??public synchronized boolean contains(Object value)
2、是否包含某个key
??public synchronized boolean containsKey(Object key)
3、是否包含某个Value
??public boolean containsValue(Object value)

??使用示例:

        Hashtable<String, Integer> wordCount = new Hashtable<>();
        wordCount.put("Yiidian", 1);
        wordCount.put("for", 2);
        wordCount.put("Java", 3);
        System.out.println(wordCount.contains(1));  //true
        System.out.println(wordCount.containsValue(1));  //true
        System.out.println(wordCount.containsKey("PHP"));  //false

2.8 elements

返回此散列表中值的枚举
??public synchronized Enumeration< V > elements()

??使用示例:

        Hashtable<String, Integer> wordCount = new Hashtable<>();
        wordCount.put("Yiidian", 1);
        wordCount.put("for", 2);
        wordCount.put("Java", 3);
        for (Enumeration en = wordCount.elements(); en.hasMoreElements();) {
            System.out.print(en.nextElement() + " ");  //3 2 1 
        }

2.9 entrySet

返回此地图中包含的映射的Set视图
??public Set<Map.Entry<K,V>> entrySet()

??使用示例:

        Hashtable<String, Integer> wordCount = new Hashtable<>();
        wordCount.put("Yiidian", 1);
        wordCount.put("for", 2);
        wordCount.put("Java", 3);
        Set s = wordCount.entrySet();
        System.out.println(s); //[Java=3, for=2, Yiidian=1]

2.10 equals

比较是否相等
??public synchronized boolean equals(Object o)

2.11 forEach

对Hashtable中的元素逐个操作
??public synchronized void forEach(BiConsumer<? super K, ? super V> action)

2.12 get

获取key对应的value
??public synchronized V get(Object key)

2.13 getOrDefault

获取key对应的value,key不存在则返回默认值
??public synchronized V getOrDefault(Object key, V defaultValue)

2.14 isEmpty

是否为空
??public synchronized boolean isEmpty()

2.15 keys

返回此散列表中键的枚举
??public synchronized Enumeration< K > keys()

??使用示例:

        Hashtable<String, Integer> wordCount = new Hashtable<>();
        wordCount.put("Yiidian", 1);
        wordCount.put("for", 2);
        wordCount.put("Java", 3);
        for (Enumeration en = wordCount.keys(); en.hasMoreElements();) {
            System.out.print(en.nextElement() + " ");  //Java for Yiidian 
        }

2.16 keySet

返回此地图中包含的键的Set视图
??public Set< K > keySet()

??使用示例:

        Hashtable<String, Integer> wordCount = new Hashtable<>();
        wordCount.put("Yiidian", 1);
        wordCount.put("for", 2);
        wordCount.put("Java", 3);
        
        Set s = wordCount.keySet();
        System.out.println(s);  //[Java, for, Yiidian]

2.17 merge

如果指定的键尚未与值相关联或与null相关联,则将其与给定的非空值相关联
??public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)

??使用示例:

        Hashtable<Integer, String> map1 = new Hashtable<>();
        map1.put(1, "L");
        map1.put(2, "M");
        map1.put(3, "N");

        Hashtable<Integer, String> map2 = new Hashtable<>();
        map2.put(1, "B");
        map2.put(2, "G");
        map2.put(3, "R");

        System.out.println("Hashtable1: " + map1.toString());  //Hashtable1: {3=N, 2=M, 1=L}
        System.out.println("Hashtable2: " + map2.toString());  //Hashtable2: {3=R, 2=G, 1=B}

        map2.forEach((key, value)-> map1.merge(
                        key, value,(v1, v2)
                                -> v1.equalsIgnoreCase(v2) ? v1 : v1 + ", " + v2));  //New Hashtable: {3=N, R, 2=M, G, 1=L, B}

        System.out.println("New Hashtable: " + map1);

2.18 put

将指定的 key映射到此 key value中指定的value
??public synchronized V put(K key, V value)

??使用示例:

        Hashtable<Integer, String> map1 = new Hashtable<>();
        map1.put(1, "L");
        map1.put(2, "M");

        System.out.println("New Hashtable: " + map1); //New Hashtable: {2=M, 1=L}

2.19 putAll

将所有从指定地图的映射复制到此散列表
??public synchronized void putAll(Map<? extends K, ? extends V> t)

??使用示例:

        Hashtable<Integer, String> map1 = new Hashtable<>();
        Hashtable<Integer, String> map2 = new Hashtable<>();
        map1.put(1, "L");
        map1.put(2, "M");
        map2.putAll(map1);

        System.out.println( map2); //{2=M, 1=L}

2.20 putIfAbsent

如果指定的键尚未与值相关联(或映射到 null )将其与给定值相关联并返回 null ,否则返回当前值
??public synchronized V putIfAbsent(K key, V value)

??使用示例:

        Map<String, String> map = new Hashtable<>();
        map.put("message", "hello");
        System.out.println("Map value before change: "+ map); //Map value before change: {message=hello}
        
        String prevvalue  = map.putIfAbsent("message", "world"); 
        System.out.println("Returned previous value:"+prevvalue); //Returned previous value:hello
        System.out.println("Map value after change: "+ map); //Map value after change: {message=hello}

2.21 remove

1、从此散列表中删除键(及其对应的值)
??public synchronized V remove(Object key)
2、仅当指定的密钥当前映射到指定的值时删除该条目
??public synchronized boolean remove(Object key, Object value)

??使用示例:

        Map<String, String> map = new Hashtable<>();
        map.put("hello", "world");
        map.put("say", "hi");
        
        System.out.println(map.remove("hello"));  //world
        System.out.println(map.remove("say","hello"));  //false

2.22 replace/replaceAll

1、只有当目标映射到某个值时,才能替换指定键的条目
??public synchronized V replace(K key, V value)
2、仅当当前映射到指定的值时,才能替换指定键的条目
??public synchronized boolean replace(K key, V oldValue, V newValue)
3、将每个条目的值替换为对该条目调用给定函数的结果,直到所有条目都被处理或该函数抛出异常
??public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function)

??使用示例:

        Map<String, String> map = new Hashtable<>();
        map.put("hello", "world");
        map.put("say", "hi");
        
        System.out.println(map.replace("hello","china")); //world
        System.out.println(map.replace("say","hi","hello")); //true
        
        map.replaceAll((key, oldValue) -> oldValue+oldValue); 
        System.out.println(map); //{hello=chinachina, say=hellohello}

2.23 size

返回此哈希表中的键数
??public synchronized int size()

2.24 toString

返回Hashtable的字符串形式
??public synchronized String toString()

??使用示例:

        Map<String, String> map = new Hashtable<>();
        map.put("hello", "world");
        map.put("say", "hi");

        System.out.println(map.toString()); //{hello=world, say=hi}

2.25 values

返回此地图中包含的值的Collection视图
??public Collection< V > values()

??使用示例:

        Map<String, String> map = new Hashtable<>();
        map.put("hello", "world");
        map.put("say", "hi");

        System.out.println(map.values()); //[world, hi]

三、Hashtable源码分析

??先看一些变量:

	//保存key-value的数组,支持泛型 
    // Entry同样采用链表解决冲突,每一个Entry本质上是一个单向链表  
    private transient Entry<?,?>[] table;
	//Entry中键值对的数量 
    private transient int count;
    //临界值 当实际大小(容量*填充因子)超过临界值时,会进行扩容
    private int threshold;
	//负载因子,当元素个数count大于总容量 * 负载因子时,扩容
    private float loadFactor;
	//Entry被改变的次数,用于fail-fast机制的实现 
    private transient int modCount = 0;
    private static final long serialVersionUID = 1421746759512286392L;

3.1 构造方法

  • 1、Hashtable()
    //无参构造方法
    public Hashtable() {
        //默认容量大小为11,负载因子设置为0.75
        this(11, 0.75f);
    }
  • 2、Hashtable(int initialCapacity)
    //带有初始化容量大小的构造方法
    public Hashtable(int initialCapacity) {
        this(initialCapacity, 0.75f);
    }
  • 3、Hashtable(int initialCapacity, float loadFactor)
    public Hashtable(int initialCapacity, float loadFactor) {
    
        //检查参数的合法性
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal Load: "+loadFactor);
 
        //如果设置初始容量为0,则默认修改为1
        if (initialCapacity==0)
            initialCapacity = 1;
        //设置负载因子
        this.loadFactor = loadFactor;
        
        //根据设置的初始化容量创建数组
        table = new Entry<?,?>[initialCapacity];
 
      
        //计算阈值,取初始化容量与可分配的最大容量中的最小值。
        threshold = (int)Math.min(initialCapacity, MAX_ARRAY_SIZE + 1);
    }
  • 4、Hashtable(int initialCapacity, float loadFactor)
    //使用Map集合初始化
    public Hashtable(Map<? extends K, ? extends V> t) {
        // 若集合t元素大于5,则初始化容量为集合t中元素数目的2倍
        // 否则初始化容量为11
        // 负载因子设置为0.75
        this(Math.max(2*t.size(), 11), 0.75f);
        //将集合t中元素全部存储
        putAll(t);
    }
    
 
    public synchronized void putAll(Map<? extends K, ? extends V> t) {
        // for循环遍历集合t,将t中元素存储到this集合中
        for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
            //将键值对添加至集合中
            put(e.getKey(), e.getValue());
    }

3.2 获取元素

    public synchronized V get(Object key) {
        
        Entry<?,?> tab[] = table;
        //得到key的hashcode
        int hash = key.hashCode();
        //根据hashcode计算索引值
        int index = (hash & 0x7FFFFFFF) % tab.length;
        //根据index找到key对应Entry链表,遍历链表找到哈希值与键值均与key相同的元素
        for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                return (V)e.value;
            }
        }
        // 若没有找到,则返回null
        return null;
    }

3.3 存入元素

    public synchronized V put(K key, V value) {
    
        // 检验数据值的合法性
        if (value == null) {
            throw new NullPointerException();
        }
 
        Entry<?,?> tab[] = table;
        //根据键值获取索引index
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        //采用for循环方式解决哈希冲突,如果出现冲突则放在链表末尾。
        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        for(; entry != null ; entry = entry.next) {
             //当前键值key已存在,更新key的映射值value,并返回旧值
            if ((entry.hash == hash) && entry.key.equals(key)) {
                V old = entry.value;
                entry.value = value;
                return old;
            }
        }
 
        //若没有找到重复键值key,则将key和value添加链表末尾
        addEntry(hash, key, value, index);
        return null;
    }
    
    //添加元素
    private void addEntry(int hash, K key, V value, int index) {
    
    
        modCount++;
 
        Entry<?,?> tab[] = table;
        
        //判断当前数目是否超过阈值
        if (count >= threshold) {
            // 数目超过阈值,扩容
            rehash();
 
            //更新扩容后的数组信息
            tab = table;
            hash = key.hashCode();
            index = (hash & 0x7FFFFFFF) % tab.length;
        }
 
        // 没有超过阈值,则添加至数组中
        @SuppressWarnings("unchecked")
        Entry<K,V> e = (Entry<K,V>) tab[index];
        tab[index] = new Entry<>(hash, key, value, e);
        
        //增加元素数目
        count++;
    }
    
    //扩容方法
    protected void rehash() {
     
        //获取旧数组大小
        int oldCapacity = table.length;
        Entry<?,?>[] oldMap = table;
 
        // 创建新容量大小的Entry数组,数组容量大小为原数组的2倍+1  
        int newCapacity = (oldCapacity << 1) + 1;
        if (newCapacity - MAX_ARRAY_SIZE > 0) {
            if (oldCapacity == MAX_ARRAY_SIZE)
                // Keep running with MAX_ARRAY_SIZE buckets
                return;
            newCapacity = MAX_ARRAY_SIZE;
        }
       Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
 
        modCount++;
        
        //重新计算阈值
        threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
        table = newMap;
 
        //将原数组中元素拷贝至新数组
       for (int i = oldCapacity ; i-- > 0 ;) {
            for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
                Entry<K,V> e = old;
                old = old.next;
 
                int index = (e.hash & 0x7FFFFFFF) % newCapacity;
                e.next = (Entry<K,V>)newMap[index];
                newMap[index] = e;
            }
        }
    }

3.4 判断是否包含某个key/value

    //判断是否含有value
    public boolean containsValue(Object value) {
        return contains(value);
    }
    
    public synchronized boolean contains(Object value) {
    
        //检查参数的合法性
        if (value == null) {
            throw new NullPointerException();
        }
 
        // 双重for循环,外循环遍历数组,内循环遍历链表
        Entry<?,?> tab[] = table;
        for (int i = tab.length ; i-- > 0 ;) {
            for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) {
                if (e.value.equals(value)) {
                    return true;
                }
            }
        }
        return false;
    }
    
    // 判断是否包含键值key
   public synchronized boolean containsKey(Object key) {
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        // index定位数组位置,for遍历链表查找元素
        for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                return true;
            }
        }
        return false;
    }

3.5 替换元素

public synchronized V replace(K key, V value) {
        Objects.requireNonNull(value);
        //根据键值查找元素
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        @SuppressWarnings("unchecked")
        Entry<K,V> e = (Entry<K,V>)tab[index];
        for (; e != null; e = e.next) {
             //查找成功,替换元素值
            if ((e.hash == hash) && e.key.equals(key)) {
                V oldValue = e.value;
                e.value = value;
                return oldValue;
            }
        }
        return null;
    }

3.6 删除元素

//根据键值删除元素,返回被删除元素值
public synchronized V remove(Object key) {
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        @SuppressWarnings("unchecked")
        Entry<K,V> e = (Entry<K,V>)tab[index];
         //for遍历链表查找元素
        for(Entry<K,V> prev = null ; e != null ; prev = e, e = e.next) {
            //查找到元素进行链表的节点删除操作
            if ((e.hash == hash) && e.key.equals(key)) {
                modCount++;
                if (prev != null) {
                    prev.next = e.next;
                } else {
                    tab[index] = e.next;
                }
                count--;
                V oldValue = e.value;
                e.value = null;
                return oldValue;
            }
        }
        return null;
    }

3.7 获取value集合

public synchronized Enumeration<V> elements() {
        return this.<V>getEnumeration(VALUES);
    }
 
    // 获取Hashtable的枚举类对象    
    // 若Hashtable的实际大小为0,则返回“空枚举类”对象;    
    // 否则,返回正常的Enumerator的对象。
private <T> Enumeration<T> getEnumeration(int type) {
        if (count == 0) {
            return Collections.emptyEnumeration();
        } else {
            return new Enumerator<>(type, false);
        }
    }
 
    // 获取Hashtable的迭代器    
    // 若Hashtable的实际大小为0,则返回“空迭代器”对象;    
    // 否则,返回正常的Enumerator的对象。(Enumerator实现了迭代器和枚举两个接口) 
private <T> Iterator<T> getIterator(int type) {
        if (count == 0) {
            return Collections.emptyIterator();
        } else {
            return new Enumerator<>(type, true);
        }
    }
 
 
// Enumerator的作用是提供了“通过elements()遍历Hashtable的接口” 和 “通过entrySet()遍历Hashtable的接口”。    
private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
        // 指向Hashtable的table   
        Entry<?,?>[] table = Hashtable.this.table;
        // Hashtable的总的大小  
        int index = table.length;
        Entry<?,?> entry;
        Entry<?,?> lastReturned;
        int type;
 
        // Enumerator是 “迭代器(Iterator)” 还是 “枚举类(Enumeration)”的标志    
        // iterator为true,表示它是迭代器;否则,是枚举类。
        boolean iterator;
 
        // 在将Enumerator当作迭代器使用时会用到,用来实现fail-fast机制
        protected int expectedModCount = modCount;
 
        Enumerator(int type, boolean iterator) {
            this.type = type;
            this.iterator = iterator;
        }
 
        // 从遍历table的数组的末尾向前查找,直到找到不为null的Entry。  
        public boolean hasMoreElements() {
            Entry<?,?> e = entry;
            int i = index;
            Entry<?,?>[] t = table;
            /* Use locals for faster loop iteration */
            while (e == null && i > 0) {
                e = t[--i];
            }
            entry = e;
            index = i;
            return e != null;
        }
 
        // 获取下一个元素    
        // 注意:从hasMoreElements() 和nextElement() 可以看出“Hashtable的elements()遍历方式”    
        // 首先,<span style="color:#ff0000;">从后向前的遍历table数组</span>。table数组的每个节点都是一个单向链表(Entry)。    
        // 然后,依次向后遍历单向链表Entry。    
        @SuppressWarnings("unchecked")
        public T nextElement() {
            Entry<?,?> et = entry;
            int i = index;
            Entry<?,?>[] t = table;
            /* Use locals for faster loop iteration */
            while (et == null && i > 0) {
                et = t[--i];
            }
            entry = et;
            index = i;
            if (et != null) {
                Entry<?,?> e = lastReturned = entry;
                entry = e.next;
                return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
            }
            throw new NoSuchElementException("Hashtable Enumerator");
        }
 
        // Iterator methods
        public boolean hasNext() {
            return hasMoreElements();
        }
 
        public T next() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            return nextElement();
        }
 
        public void remove() {
            if (!iterator)
                throw new UnsupportedOperationException();
            if (lastReturned == null)
                throw new IllegalStateException("Hashtable Enumerator");
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
 
            synchronized(Hashtable.this) {
                Entry<?,?>[] tab = Hashtable.this.table;
                int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
 
                @SuppressWarnings("unchecked")
                Entry<K,V> e = (Entry<K,V>)tab[index];
                for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
                    if (e == lastReturned) {
                        modCount++;
                        expectedModCount++;
                        if (prev == null)
                            tab[index] = e.next;
                        else
                            prev.next = e.next;
                        count--;
                        lastReturned = null;
                        return;
                    }
                }
                throw new ConcurrentModificationException();
            }
        }
    }

3.8 常用方法

方法名含义时间复杂度
get(Object key)根据key值获取元素O(1)
put(K key, V value)添加元素O(n)
putAll()添加Hashtable 中元素O(n)
contains(Object value)判断是否包含元素O(n)
containsValue(Object value)判断是否包含元素O(n)
containsKey(Object key)判断是否包含keyO(1)
replace(K key, V oldValue, V newValue)替换元素值O(1)
size()获取元素数目O(1)
isEmpty()判断Hashtable 是否为空O(1)
remove(Object key)根据键值删除元素O(n)
clear()清空HashtableO(n)
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-09-09 11:36:30  更:2021-09-09 11:38:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 16:59:23-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码