本文学习HashTable,这是一个古老类,基本上被废除,但是学习它有助于理解HashMap。
HashTable简介
HashTable是一个key-value键值对的数据类型,较为古老,现已基本废除不再使用,使用synchronized保证同步,效率较低,一般单线程转为使用HashMap,多线程使用ConcurrentHashMap。
但学习其实现方式有助于理解hashMap的实现。
HashTable继承关系
继承Dictionary类,实现Map接口。
HashTable原理
hashTable的原理和hashMap大致相同。在一些算法和设计方面,hashTable比hashMap低下。
HashTable属性
//节点数组private transient Entry<?,?>[] table;//节点个数private transient int count;//临界值private int threshold;//加载因子 0.75private float loadFactor;//模数,hashTable被修改的次数private transient int modCount = 0;
HashTable插入元素
当key值重复,就覆盖并返回旧的value
当key值不重复,直接插入。如果出现冲突,拉链发解决
一、(hash & 0x7FFFFFFF) % tab.length;
取余操作,获取散列下标,相比于hashMap的一次位运算,这里效率很低。
这里巧妙在于,与0x7FFFFFFF进行与运算,避免负数的出现
public synchronized V put(K key, V value) {    // Make sure the value is not null    //不允许插入null值    if (value == null) {        throw new NullPointerException();    }    // Makes sure the key is not already in the hashtable.    Entry<?,?> tab[] = table;    //这里并没有对key进行为空检测,是不合理的    int hash = key.hashCode();    //hash值与0x7FFFFFFF按位与,防止出现负数。    //与tab.length做取余操作,得到散列下标    int index = (hash & 0x7FFFFFFF) % tab.length;    @SuppressWarnings("unchecked")    Entry<K,V> entry = (Entry<K,V>)tab[index];    //不为空    for(; entry != null ; entry = entry.next) {        //出现重复则覆盖        if ((entry.hash == hash) && entry.key.equals(key)) {            V old = entry.value;            entry.value = value;            return old;        }    }    //出现冲突、或对应下标节点为空,插入元素    addEntry(hash, key, value, index);    return null;}    addEntry方法
如果节点个数超过临界值,就扩容。
否则直接插入元素,或拉链法解决冲突
private void addEntry(int hash, K key, V value, int index) {    modCount++;    Entry<?,?> tab[] = table;    if (count >= threshold) {        // Rehash the table if the threshold is exceeded        rehash();        tab = table;        hash = key.hashCode();        index = (hash & 0x7FFFFFFF) % tab.length;    }    // Creates the new entry.    @SuppressWarnings("unchecked")    Entry<K,V> e = (Entry<K,V>) tab[index];    tab[index] = new Entry<>(hash, key, value, e);    count++;}    rehash()方法
这里的扩容方法,只是简单的将节点散列到新的数组上,并没有做将链表变短的操作。
protected void rehash() {    int oldCapacity = table.length;    Entry<?,?>[] oldMap = table;    // overflow-conscious code    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 ;) {        //i下标对单向链表        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;        }    }}    拉链发解决冲突图示:
Properties简介
Properties 继承于 Hashtable,可以作为一个map使用。其内部扩展了一些方法,只允许添加String的key-value,不过都是基于hashTable实现的。其使用最多的是作为配置工具类使用。
使用
properties作为map使用
/** * properties作为map使用 */@Testpublic void propertiesUseAsMap() {    Properties prop = new Properties();    prop.put(1, "a");    prop.put(2, 2);    prop.put("3", new Object());    System.out.println(prop.get(1));    System.out.println(prop.get(2));    System.out.println(prop.get("3"));}    其扩展方法,只能添加字符串的key-valu
@Testpublic void useAsProp() {Properties prop = new Properties();prop.setProperty("name","name");prop.setProperty("age","23");prop.setProperty("email","123@qq.com");System.out.println(prop);prop.forEach((key, value) -> {System.out.println("{key" + key + "," + "value" + value + "}");});}     有一些类自带properties属性
/*** 也可以自己写一个配置类*/@Testpublic void testMyCP() {Properties prop = MyPropClass.getProperties(); System.out.println(prop);prop.forEach((key, value) -> {    System.out.println("{key" + key + "," + "value" + value + "}");});}
class MyPropClass { private static Properties props; private static final String name; private static final String age; private static final String email;
static {    props = new Properties();    name = "yyc";    age = "23";    email = "123@qq.com";    initProperties();}private static void initProperties() {    props.setProperty("name", name);    props.setProperty("age", age);    props.setProperty("email", email);}public void setProperties(String key, String value) {    props.setProperty(key, value);}public String getProperties(String key) {    return props.getProperty(key);}public void setProperties(Properties properties) {    MyPropClass.props = properties;}public static Properties getProperties() {    return props;}> 为了防止一些硬编码,可以使用配置文件的形式配置信息,一般用于数据库链接或一些配置的类信息。user.properties:```propertiesname=yycage=23hobby=ball
public synchronized V put(K key, V value) {    // Make sure the value is not null    //不允许插入null值    if (value == null) {        throw new NullPointerException();    }    // Makes sure the key is not already in the hashtable.    Entry<?,?> tab[] = table;    //这里并没有对key进行为空检测,是不合理的    int hash = key.hashCode();    //hash值与0x7FFFFFFF按位与,防止出现负数。    //与tab.length做取余操作,得到散列下标    int index = (hash & 0x7FFFFFFF) % tab.length;    @SuppressWarnings("unchecked")    Entry<K,V> entry = (Entry<K,V>)tab[index];    //不为空    for(; entry != null ; entry = entry.next) {        //出现重复则覆盖        if ((entry.hash == hash) && entry.key.equals(key)) {            V old = entry.value;            entry.value = value;            return old;        }    }    //出现冲突、或对应下标节点为空,插入元素    addEntry(hash, key, value, index);    return null;}0    同时也可以将Properties作为文件输出
public synchronized V put(K key, V value) {    // Make sure the value is not null    //不允许插入null值    if (value == null) {        throw new NullPointerException();    }    // Makes sure the key is not already in the hashtable.    Entry<?,?> tab[] = table;    //这里并没有对key进行为空检测,是不合理的    int hash = key.hashCode();    //hash值与0x7FFFFFFF按位与,防止出现负数。    //与tab.length做取余操作,得到散列下标    int index = (hash & 0x7FFFFFFF) % tab.length;    @SuppressWarnings("unchecked")    Entry<K,V> entry = (Entry<K,V>)tab[index];    //不为空    for(; entry != null ; entry = entry.next) {        //出现重复则覆盖        if ((entry.hash == hash) && entry.key.equals(key)) {            V old = entry.value;            entry.value = value;            return old;        }    }    //出现冲突、或对应下标节点为空,插入元素    addEntry(hash, key, value, index);    return null;}1原文:https://juejin.cn/post/7103534218403135525