HsqlDB源码学习——BaseHashMap的实现

通过开源软件学数据结构:

data store:
    keys: {array of primitive | array of object}
    values: {none | array of primitive | array of object} same size as keys
    objects support : hashCode(), equals()

    implemented types of keyTable:
    {objectKeyTable: variable size Object[] array for keys |
    intKeyTable: variable size int[] for keys |
    longKeyTable: variable size long[] for keys }

    implemented types of valueTable:
    {
        objectValueTable: variable size Object[] array for values |
        intValueTable: variable size int[] for values |
        longValueTable: variable size long[] for values
    }

    valueTable does not exist for sets or for object pools

    hash index:
    hashTable: fixed size int[] array for hash lookup into keyTable
    linkTable: pointer to the next key ; size equal or larger than hashTable but equal to the valueTable

    access count table:
    {
        none |variable size int[] array for access count
    } same size as xxxKeyTable
HashIndex数组使用情况:
HsqlDB源码学习——BaseHashMap的实现_第1张图片 

          通过api对BaseHashMap的介绍可以看到他主要由KeyTable,ValueTable(包括int,long,object类型的Table,这里主要讨论int类型的),还有HashIndex中的HashTable,LinkTable四个类型的数组组成。
           假设:IntKeyTable,ValueTable,LinkTable为length=6的数组,HashIndex为length=3的数组。
           
           输入key的HashCode为:0,1,2,3,4,5
   看下大概的原理图:

           接下来通过插入这几个hashcode的值来看他hashmap的实现!
         /**
	 * type-specific method for adding or removing keys in long or int->Object
	 * maps
	 */
	protected Object addOrRemove(long longKey, Object objectValue,Object objectValueTwo, boolean remove) {
		int hash = (int) longKey;
		int index = hashIndex.getHashIndex(hash);   #1
		int lookup = hashIndex.hashTable[index];    #2
		int lastLookup = -1;
		Object returnValue = null;
		for (; lookup >= 0; lastLookup = lookup, lookup = hashIndex.getNextLookup(lookup)) {//根据LinkTable的顺序进行查找   #3
			if (isIntKey) {
				if (longKey == intKeyTable[lookup]) {
					break;
				}
			} else {
				if (longKey == longKeyTable[lookup]) {
					break;
				}
			}
		}
                //如果找到的话lookup>=0
		if (lookup >= 0) {
			if (remove) {
				if (longKey == 0) {
					hasZeroKey = false;
					zeroKeyIndex = -1;
				}

				if (isIntKey) {
					intKeyTable[lookup] = 0;
				} else {
					longKeyTable[lookup] = 0;
				}

				returnValue = objectValueTable[lookup];
				objectValueTable[lookup] = null;

				hashIndex.unlinkNode(index, lastLookup, lookup);          

				if (isTwoObjectValue) {
					objectKeyTable[lookup] = null;
				}

				if (accessTable != null) {
					accessTable[lookup] = 0;
				}

				return returnValue;
			}

			if (isObjectValue) {
				returnValue = objectValueTable[lookup];
				objectValueTable[lookup] = objectValue;
			}

			if (isTwoObjectValue) {
				objectKeyTable[lookup] = objectValueTwo;
			}

			if (accessTable != null) {
				accessTable[lookup] = ++accessCount;
			}

			return returnValue;
		}

		// not found
		if (remove) {
			return returnValue;
		}

		if (hashIndex.elementCount >= threshold) {
			if (reset()) {
				return addOrRemove(longKey, objectValue, objectValueTwo, remove);
			} else {
				return null;
			}
		}

		lookup = hashIndex.linkNode(index, lastLookup);           #4

		if (isIntKey) {
			intKeyTable[lookup] = (int) longKey;
		} else {
			longKeyTable[lookup] = longKey;
		}

		if (longKey == 0) {
			hasZeroKey = true;
			zeroKeyIndex = lookup;
		}

		objectValueTable[lookup] = objectValue;

		if (isTwoObjectValue) {
			objectKeyTable[lookup] = objectValueTwo;
		}

		if (accessTable != null) {
			accessTable[lookup] = ++accessCount;
		}

		return returnValue;
	}
#1源码:
	/**
	 * @param hash
	 */
	public int getHashIndex(int hash) {
		return (hash & 0x7fffffff) % hashTable.length; #1.1
	}
#1.1 就是根据HashTable的长度做了一个模运算!为了方便看结果所以上面假设HashTable的length是3!
#2就是根据获得的HashTable的索引获取该索引处的值,如果第一次获取的话是-1,如果不是第一次,便是具有相同index的link的第一个元素的值。
看下HashTable的初始化:
public void resetTables() {
		int to = hashTable.length;
		int[] intArray = hashTable;
		while (--to >= 0) {
	           intArray[to] = -1;        //初始化为-1
		}
		newNodePointer = 0;
		elementCount = 0;
		reclaimedNodePointer = -1;
		modified = false;
	}
初始状态,HashTable的值都是-1.
#3的源码:
/**
     * This looks from a given node, so the parameter is always > -1.
     *
     * @param lookup A valid node to look from
     * @return either -1 or the next node from this node
     */
    public int getNextLookup(int lookup) {
        return linkTable[lookup];
    }
#4是在没有找到相同的内容,并且元素数量没有超过map的最大容量的情况下插入的:
/**
     * Link a new node to the end of the linked for a hash index.
     *
     * @param index an index into hashTable
     * @param lastLookup either -1 or the node to which the new node will be linked
     * @return the new node
     */
    public int linkNode(int index, int lastLookup) {

        // get the first reclaimed slot
        int lookup = reclaimedNodePointer;    #5

        if (lookup == -1) {
            lookup = newNodePointer++;    #6
        } else {
            // reset the first reclaimed slot
            reclaimedNodePointer = linkTable[lookup];   #7
        }
        // link the node
        if (lastLookup == -1) {
            hashTable[index] = lookup;   #8
        } else {
            linkTable[lastLookup] = lookup;  #9
        }

        linkTable[lookup] = -1;   #10

        elementCount++;    #11

        modified = true;

        return lookup;
    }
#5 reclaimedNodePointer初始化是-1,表示没有可循环利用的空间链表,在没有空闲链表的情况下执行了#6,newNodePointer的值是elementCount的值是一致的。
如果不是第二个插入元素的话,便会执行#9将当前的IntKeyTable的index值放入LinkTable中索引为lastLookup的值中。并且设置这个队列的末尾表示符,通过#10来完成的。然后IntKeyTable中的元素加一(#11)。


你可能感兴趣的:(thread,HashMap,数组,HSQLDB)