jdk1.7的HashMap重写以及与1.8的比较

本文详细介绍了JDK 1.7中HashMap的实现机制,包括通过hash算法计算下标、超过0.75负载因子时的自动扩容以及在put操作中的处理。并通过实现一个MyHashMap类来模拟HashMap的逻辑。在测试过程中观察到扩容过程。接着,对比了JDK 1.7与1.8在HashMap数据结构上的差异。

如上图,HashMap是一个链表结构,获取位置下标的时候是通过hash算法来计算下标位置,同时,在存放的值超过整个容量的0.75之后会自动扩容,而且扩容之后需要重新获取entry的next指针,并且在put的时候要进行判断,这个操作是新增还是修改.

首先,定义一个MyMap接口,包含三个方法以及键值对对象:

public interface MyMap<K, V> {
    // 向集合中插入值
    public V put( K k, V v );

    // 根据key获取集合中的值
    public V get( K k );

    // 获得集合中元素个数
    public int size();

    // 用于获取集合中,键值对的对象
    interface Entry<K, V> {
        K getKey();

        V getValue();

        V setValue( V value );

        Entry<K, V> getNext();

        Entry<K, V> setNext( Entry<K, V> next );
    }
}

然后,定义MyHashMap继承上方接口,按照HashMap的实现逻辑去一步步实现:

public class MyHashMap<K, V> implements MyMap<K, V> {
    /**
     * 根据hash算法,理论上只需要查找一次就能查找到值
     * Entry 类型数组,默认长度16
     */
    private Entry<K, V>   table[]       = null;

    // Hashmap的元素个数
    private int           size;

    // hashmap集合中的数组的默认长度
    private static int    defaultLength = 16;

    // 定义hashmap的加载银子0.75
    private static double defaltLoad    = 0.75f;

    @Override
    public V put( K k, V v ) {
        if ( table == null ) {
            table = new Entry[this.defaultLength];
        }

        if ( size >= this.defaultLength * this.defaltLoad ) {
            // 扩容
            resize();
        }

        // 1.分院,确定key/value存放吃的数组的下标位置
        int index = getIndex( k, this.defaultLength );

        // 判断是不是修改
        MyMap.Entry<K, V> entry = table[ index ];
        while( entry != null ) {
            if ( entry.getKey()
                      .equals( k ) ) {
                return entry.setValue( v );
            } else {
                entry = entry.getNext();
            }
        }
        // 2.创建元素,并且存放在table的index下标上
        table[ index ] = new Entry<>( k, v, table[ index ] );
        this.size++;
        return v;
    }

    private void resize() {
        // 重新散列
        if ( size >= this.defaultLength * this.defaltLoad ) {
            System.out.println( "扩容开始..." );
            Entry<K, V> newTable[] = new Entry[this.defaultLength << 1];
            MyMap.Entry<K, V> entry = null;
            for( int i = 0; i < table.length; i++ ) {
                entry = table[ i ];
                while( entry != null ) {
                    int index = getIndex( entry.getKey(), newTable.length );

                    MyMap.Entry<K, V> oldEntry = entry.getNext();
                    entry.setNext( newTable[ index ] );

                    newTable[ index ] = (Entry<K, V>) entry;
                    // 继续下一个节点
                    entry = oldEntry;
                }
            }
            table = newTable;
            this.defaultLength = newTable.length;
            newTable = null;
        }
    }

    public int getIndex( K k, int length ) {
        if ( k == null ) {
            return 0;
        }
        int hash = k.hashCode();
        // 与算法 & 取模
        return hash & ( length - 1 );
    }

    @Override
    public V get( K k ) {
        if ( table != null ) {
            int index = getIndex( k, this.defaultLength );
            MyMap.Entry<K, V> entry = table[ index ];
            while( entry != null ) {
                if ( entry.getKey()
                          .equals( k ) ) {
                    return entry.getValue();
                } else {
                    entry = entry.getNext();
                }
            }
        }
        return null;
    }

    @Override
    public int size() {
        return this.size;
    }

    // Entry
    static class Entry<K, V> implements MyMap.Entry<K, V> {

        K                 key;

        V                 value;

        MyMap.Entry<K, V> next;

        public Entry( K key, V value, MyMap.Entry<K, V> next ) {
            super();
            this.key = key;
            this.value = value;
            this.next = next;
        }

        @Override
        public K getKey() {
            return this.key;
        }

        @Override
        public V getValue() {
            // TODO Auto-generated method stub
            return this.value;
        }

        @Override
        public V setValue( V value ) {
            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }

        @Override
        public MyMap.Entry<K, V> getNext() {
            return this.next;
        }

        @Override
        public MyMap.Entry<K, V> setNext( MyMap.Entry<K, V> next ) {
            MyMap.Entry<K, V> oldNext = this.next;
            this.next = next;
            return oldNext;
        }

    }
}

最后,测试:

public class Test {

    public static void main( String[] args ) {
        MyHashMap<String, String> map = new MyHashMap<>();
        map.put( "1号", "打的" );
        map.put( "2号", "大的" );
        map.put( "3号", "的的" );
        map.put( "4号", "改动的" );
        map.put( "5号", "改个的" );
        map.put( "6号", "更大的" );
        map.put( "7号", "发" );
        map.put( "8号", "发呆" );
        map.put( "9号", "更大" );
        map.put( "10号", "更大啊" );
        map.put( "11号", "啊" );
        map.put( "12号", "个" );
        map.put( "13号", "人" );
        map.put( "14号", "让的" );
        map.put( "15号", "个的" );
        map.put( "16号", "发给谁" );
        map.put( "17号", "但是" );
        map.put( "18号", "凡事" );
        map.put( "19号", "给谁" );
        map.put( "20号", "凡事" );
        map.put( "21号", "胜多负少" );
        map.put( "22号", "发顺丰" );
        map.put( "23号", "凡事的" );
        map.put( "24号", "凡事发的" );
        map.put( "25号", "发呆" );
        map.put( "26号", "佛挡杀佛 " );
        map.put( "27号", "凡事的" );
        map.put( "28号", "凡事发多少" );
        map.put( "29号", "发生的的" );
        map.put( "30号", "凡事的" );
        map.put( "31号", "fsfds" );
        map.put( "32号", "萨芬" );

        System.out.println( map.get( "17号" ) );
    }
}

测试结果:扩容开始...
                扩容开始...
                但是

下面我们看看与1.8的差别:

以及数据结构的差别:

至此,我们可以看出两者之间的差别.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值