源码来源地址:https://github.com/netty/netty/tree/4.0

不恰当的数据结构导致内存在占用过大。这个问题,就完全可以使用 Netty 的IntObjectHashMap 数据结构来解决,只需要换个类,就可以节省非常多的资源。

相同点:

IntObjectHashMap和HashMap都是以键值对的形式,储存对象。

不同点:

IntObjectHashMap的键只能是int类型,值是Object类型。

HashMap的键和值都是Object类型。

目录

一、IntObjectMap.java

二、IntObjectHashMap.java


一、IntObjectMap.java

package com;import java.util.Collection;/*** Interface for a primitive map that uses {@code int}s as keys.** @param <V> the value type stored in the map.*/
public interface IntObjectMap<V> {/*** An Entry in the map.** @param <V> the value type stored in the map.*/interface Entry<V> {/*** Gets the key for this entry.*/int key();/*** Gets the value for this entry.*/V value();/*** Sets the value for this entry.*/void setValue(V value);}/*** Gets the value in the map with the specified key.** @param key the key whose associated value is to be returned.* @return the value or {@code null} if the key was not found in the map.*/V get(int key);/*** Puts the given entry into the map.** @param key   the key of the entry.* @param value the value of the entry.* @return the previous value for this key or {@code null} if there was no*         previous mapping.*/V put(int key, V value);/*** Puts all of the entries from the given map into this map.*/void putAll(IntObjectMap<V> sourceMap);/*** Removes the entry with the specified key.** @param key the key for the entry to be removed from this map.* @return the previous value for the key, or {@code null} if there was no*         mapping.*/V remove(int key);/*** Returns the number of entries contained in this map.*/int size();/*** Indicates whether or not this map is empty (i.e {@link #size()} ==* {@code 0]).*/boolean isEmpty();/*** Clears all entries from this map.*/void clear();/*** Indicates whether or not this map contains a value for the specified key.*/boolean containsKey(int key);/*** Indicates whether or not the map contains the specified value.*/boolean containsValue(V value);/*** Gets an iterable collection of the entries contained in this map.*/Iterable<Entry<V>> entries();/*** Gets the keys contained in this map.*/int[] keys();/*** Gets the values contained in this map.*/V[] values(Class<V> clazz);/*** Gets the values contatins in this map as a {@link Collection}.*/Collection<V> values();
}

二、IntObjectHashMap.java

package com;/** Copyright 2014 The Netty Project** The Netty Project licenses this file to you under the Apache License, version 2.0 (the* "License"); you may not use this file except in compliance with the License. You may obtain a* copy of the License at:** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software distributed under the License* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express* or implied. See the License for the specific language governing permissions and limitations under* the License.*/import java.lang.reflect.Array;
import java.util.AbstractCollection;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;/*** A hash map implementation of {@link IntObjectMap} that uses open addressing* for keys. To minimize the memory footprint, this class uses open addressing* rather than chaining. Collisions are resolved using linear probing. Deletions* implement compaction, so cost of remove can approach O(N) for full maps,* which makes a small loadFactor recommended.** @param <V> The value type stored in the map.*/
public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectMap.Entry<V>> {/** Default initial capacity. Used if not specified in the constructor */private static final int DEFAULT_CAPACITY = 11;/** Default load factor. Used if not specified in the constructor */private static final float DEFAULT_LOAD_FACTOR = 0.5f;/*** Placeholder for null values, so we can use the actual null to mean available.* (Better than using a placeholder for available: less references for GC* processing.)*/private static final Object NULL_VALUE = new Object();/** The maximum number of elements allowed without allocating more space. */private int maxSize;/** The load factor for the map. Used to calculate {@link #maxSize}. */private final float loadFactor;private int[] keys;private V[] values;private Collection<V> valueCollection;private int size;public IntObjectHashMap() {this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR);}public IntObjectHashMap(int initialCapacity) {this(initialCapacity, DEFAULT_LOAD_FACTOR);}public IntObjectHashMap(int initialCapacity, float loadFactor) {if (initialCapacity < 1) {throw new IllegalArgumentException("initialCapacity must be >= 1");}if (loadFactor <= 0.0f || loadFactor > 1.0f) {// Cannot exceed 1 because we can never store more than capacity elements;// using a bigger loadFactor would trigger rehashing before the desired load is// reached.throw new IllegalArgumentException("loadFactor must be > 0 and <= 1");}this.loadFactor = loadFactor;// Adjust the initial capacity if necessary.int capacity = adjustCapacity(initialCapacity);// Allocate the arrays.keys = new int[capacity];@SuppressWarnings({ "unchecked", "SuspiciousArrayCast" })V[] temp = (V[]) new Object[capacity];values = temp;// Initialize the maximum size value.maxSize = calcMaxSize(capacity);}private static <T> T toExternal(T value) {return value == NULL_VALUE ? null : value;}@SuppressWarnings("unchecked")private static <T> T toInternal(T value) {return value == null ? (T) NULL_VALUE : value;}@Overridepublic V get(int key) {int index = indexOf(key);return index == -1 ? null : toExternal(values[index]);}@Overridepublic V put(int key, V value) {int startIndex = hashIndex(key);int index = startIndex;for (;;) {if (values[index] == null) {// Found empty slot, use it.keys[index] = key;values[index] = toInternal(value);growSize();return null;}if (keys[index] == key) {// Found existing entry with this key, just replace the value.V previousValue = values[index];values[index] = toInternal(value);return toExternal(previousValue);}// Conflict, keep probing ...if ((index = probeNext(index)) == startIndex) {// Can only happen if the map was full at MAX_ARRAY_SIZE and couldn't grow.throw new IllegalStateException("Unable to insert");}}}private int probeNext(int index) {return index == values.length - 1 ? 0 : index + 1;}@Overridepublic void putAll(IntObjectMap<V> sourceMap) {if (sourceMap instanceof IntObjectHashMap) {// Optimization - iterate through the arrays.IntObjectHashMap<V> source = (IntObjectHashMap<V>) sourceMap;for (int i = 0; i < source.values.length; ++i) {V sourceValue = source.values[i];if (sourceValue != null) {put(source.keys[i], sourceValue);}}return;}// Otherwise, just add each entry.for (Entry<V> entry : sourceMap.entries()) {put(entry.key(), entry.value());}}@Overridepublic V remove(int key) {int index = indexOf(key);if (index == -1) {return null;}V prev = values[index];removeAt(index);return toExternal(prev);}@Overridepublic int size() {return size;}@Overridepublic boolean isEmpty() {return size == 0;}@Overridepublic void clear() {Arrays.fill(keys, 0);Arrays.fill(values, null);size = 0;}@Overridepublic boolean containsKey(int key) {return indexOf(key) >= 0;}@Overridepublic boolean containsValue(V value) {V v1 = toInternal(value);for (V v2 : values) {// The map supports null values; this will be matched as// NULL_VALUE.equals(NULL_VALUE).if (v2 != null && v2.equals(v1)) {return true;}}return false;}@Overridepublic Iterable<Entry<V>> entries() {return this;}@Overridepublic Iterator<Entry<V>> iterator() {return new IteratorImpl();}@Overridepublic int[] keys() {int[] outKeys = new int[size()];int targetIx = 0;for (int i = 0; i < values.length; ++i) {if (values[i] != null) {outKeys[targetIx++] = keys[i];}}return outKeys;}@Overridepublic V[] values(Class<V> clazz) {@SuppressWarnings("unchecked")V[] outValues = (V[]) Array.newInstance(clazz, size());int targetIx = 0;for (V value : values) {if (value != null) {outValues[targetIx++] = value;}}return outValues;}@Overridepublic Collection<V> values() {Collection<V> valueCollection = this.valueCollection;if (valueCollection == null) {this.valueCollection = valueCollection = new AbstractCollection<V>() {@Overridepublic Iterator<V> iterator() {return new Iterator<V>() {final Iterator<Entry<V>> iter = IntObjectHashMap.this.iterator();@Overridepublic boolean hasNext() {return iter.hasNext();}@Overridepublic V next() {return iter.next().value();}@Overridepublic void remove() {throw new UnsupportedOperationException();}};}@Overridepublic int size() {return size;}};}return valueCollection;}@Overridepublic int hashCode() {// Hashcode is based on all non-zero, valid keys. We have to scan the whole keys// array, which may have different lengths for two maps of same size(), so the// capacity cannot be used as input for hashing but the size can.int hash = size;for (int key : keys) {// 0 can be a valid key or unused slot, but won't impact the hashcode in either// case.// This way we can use a cheap loop without conditionals, or hard-to-unroll// operations,// or the devastatingly bad memory locality of visiting value objects.// Also, it's important to use a hash function that does not depend on the// ordering// of terms, only their values; since the map is an unordered collection and// entries can end up in different positions in different maps that have the// same// elements, but with different history of puts/removes, due to conflicts.hash ^= key;}return hash;}@Overridepublic boolean equals(Object obj) {if (this == obj) {return true;}if (!(obj instanceof IntObjectMap)) {return false;}@SuppressWarnings("rawtypes")IntObjectMap other = (IntObjectMap) obj;if (size != other.size()) {return false;}for (int i = 0; i < values.length; ++i) {V value = values[i];if (value != null) {int key = keys[i];Object otherValue = other.get(key);if (value == NULL_VALUE) {if (otherValue != null) {return false;}} else if (!value.equals(otherValue)) {return false;}}}return true;}/*** Locates the index for the given key. This method probes using double hashing.** @param key the key for an entry in the map.* @return the index where the key was found, or {@code -1} if no entry is found*         for that key.*/private int indexOf(int key) {int startIndex = hashIndex(key);int index = startIndex;for (;;) {if (values[index] == null) {// It's available, so no chance that this value exists anywhere in the map.return -1;}if (key == keys[index]) {return index;}// Conflict, keep probing ...if ((index = probeNext(index)) == startIndex) {return -1;}}}/*** Returns the hashed index for the given key.*/private int hashIndex(int key) {// Allowing for negative keys by adding the length after the first mod// operation.return (key % keys.length + keys.length) % keys.length;}/*** Grows the map size after an insertion. If necessary, performs a rehash of the* map.*/private void growSize() {size++;if (size > maxSize) {// Need to grow the arrays. We take care to detect integer overflow,// also limit array size to ArrayList.MAX_ARRAY_SIZE.rehash(adjustCapacity((int) Math.min(keys.length * 2.0, Integer.MAX_VALUE - 8)));} else if (size == keys.length) {// Open addressing requires that we have at least 1 slot available. Need to// refresh// the arrays to clear any removed elements.rehash(keys.length);}}/*** Adjusts the given capacity value to ensure that it's odd. Even capacities can* break probing.*/private static int adjustCapacity(int capacity) {return capacity | 1;}/*** Removes entry at the given index position. Also performs opportunistic,* incremental rehashing if necessary to not break conflict chains.** @param index the index position of the element to remove.*/private void removeAt(int index) {--size;// Clearing the key is not strictly necessary (for GC like in a regular// collection),// but recommended for security. The memory location is still fresh in the cache// anyway.keys[index] = 0;values[index] = null;// In the interval from index to the next available entry, the arrays may have// entries// that are displaced from their base position due to prior conflicts. Iterate// these// entries and move them back if possible, optimizing future lookups.// Knuth Section 6.4 Algorithm R, also used by the JDK's IdentityHashMap.int nextFree = index;for (int i = probeNext(index); values[i] != null; i = probeNext(i)) {int bucket = hashIndex(keys[i]);if (i < bucket && (bucket <= nextFree || nextFree <= i) || bucket <= nextFree && nextFree <= i) {// Move the displaced entry "back" to the first available position.keys[nextFree] = keys[i];values[nextFree] = values[i];// Put the first entry after the displaced entrykeys[i] = 0;values[i] = null;nextFree = i;}}}/*** Calculates the maximum size allowed before rehashing.*/private int calcMaxSize(int capacity) {// Clip the upper bound so that there will always be at least one available// slot.int upperBound = capacity - 1;return Math.min(upperBound, (int) (capacity * loadFactor));}/*** Rehashes the map for the given capacity.** @param newCapacity the new capacity for the map.*/private void rehash(int newCapacity) {int[] oldKeys = keys;V[] oldVals = values;keys = new int[newCapacity];@SuppressWarnings({ "unchecked", "SuspiciousArrayCast" })V[] temp = (V[]) new Object[newCapacity];values = temp;maxSize = calcMaxSize(newCapacity);// Insert to the new arrays.for (int i = 0; i < oldVals.length; ++i) {V oldVal = oldVals[i];if (oldVal != null) {// Inlined put(), but much simpler: we don't need to worry about// duplicated keys, growing/rehashing, or failing to insert.int oldKey = oldKeys[i];int index = hashIndex(oldKey);for (;;) {if (values[index] == null) {keys[index] = oldKey;values[index] = toInternal(oldVal);break;}// Conflict, keep probing. Can wrap around, but never reaches startIndex again.index = probeNext(index);}}}}/*** Iterator for traversing the entries in this map.*/private final class IteratorImpl implements Iterator<Entry<V>>, Entry<V> {private int prevIndex = -1;private int nextIndex = -1;private int entryIndex = -1;private void scanNext() {for (;;) {if (++nextIndex == values.length || values[nextIndex] != null) {break;}}}@Overridepublic boolean hasNext() {if (nextIndex == -1) {scanNext();}return nextIndex < keys.length;}@Overridepublic Entry<V> next() {if (!hasNext()) {throw new NoSuchElementException();}prevIndex = nextIndex;scanNext();// Always return the same Entry object, just change its index each time.entryIndex = prevIndex;return this;}@Overridepublic void remove() {if (prevIndex < 0) {throw new IllegalStateException("next must be called before each remove.");}removeAt(prevIndex);prevIndex = -1;}// Entry implementation. Since this implementation uses a single Entry, we// coalesce that// into the Iterator object (potentially making loop optimization much easier).@Overridepublic int key() {return keys[entryIndex];}@Overridepublic V value() {return toExternal(values[entryIndex]);}@Overridepublic void setValue(V value) {values[entryIndex] = toInternal(value);}}@Overridepublic String toString() {if (size == 0) {return "{}";}StringBuilder sb = new StringBuilder(4 * size);for (int i = 0; i < values.length; ++i) {V value = values[i];if (value != null) {sb.append(sb.length() == 0 ? "{" : ", ");sb.append(keyToString(keys[i])).append('=').append(value == this ? "(this Map)" : value);}}return sb.append('}').toString();}/*** Helper method called by {@link #toString()} in order to convert a single map* key into a string.*/protected String keyToString(int key) {return Integer.toString(key);}
}

IntObjectHashMap和HashMap的区别?相关推荐

  1. HashTable和HashMap的区别详解

    HashTable和HashMap的区别详解 一.HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同 ...

  2. 036_Hashtable和HashMap的区别

    1. Hashtable和HashMap的区别 1.1. Hashtable线程安全, 效率低; HashMap线程不安全, 效率高 1.2. Hashtable父类是Dictionary; Hash ...

  3. Java之HashMap系列--JDK7与JDK8的HashMap的区别

    原文网址:Java之HashMap系列--JDK7与JDK8的HashMap的区别_IT利刃出鞘的博客-CSDN博客 简介 本文介绍JDK7与JDK8的HashMap的区别. JDK7与JDK8的Ha ...

  4. HashTable和HashMap的区别(网上整理)

    1.hashtable是继承自陈旧的Dictionary类的,而hashmap继承自AbstractMap类的同时对Java1.2引进的Map接口进行了实现. 2.hashtable的方法是同步的,而 ...

  5. HashMap Hashtable区别

    •HashMap 和 Hashtable 是 Map 接口的两个典型实现类 •区别:      –Hashtable 是一个古老的 Map 实现类,不建议使用      –Hashtable 是一个线 ...

  6. hashmap删除指定key_HashTable和HashMap的区别详解

    一.HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长. HashMap是非线程安全的, ...

  7. HashMap Hashtable区别

    2019独角兽企业重金招聘Python工程师标准>>> 1.HashMap基础自AbstractMap,Hashtable继承自Dictionary   public class H ...

  8. hashmap 允许key重复吗_HashTable和HashMap的区别详解

    一.HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长. HashMap是非线程安全的, ...

  9. Hashtable 和 HashMap 的区别

    2019独角兽企业重金招聘Python工程师标准>>> 1. 类定义 这个从源码中可以直接看出来,HashMap 继承自 AbstractMap,而 Hashtabl 继承自 Dic ...

最新文章

  1. table中嵌套table,如何用jquery来控制奇偶行颜色
  2. oracle进程对文件没有写权限,ORACLE SYS用户没有权限一天半的救库过程
  3. php和python哪个工资高-前端,java,php,python工程师哪个最缺 知乎
  4. mfc 多窗口之间互相切换
  5. 通过Dapr实现一个简单的基于.net的微服务电商系统(七)——一步一步教你如何撸Dapr之服务限流...
  6. 修改 input 框里的字体、颜色
  7. HTML5 本地存储 Web Storage
  8. 转载 二叉树的创建、遍历、深度、叶子节点数
  9. android缩放动画后,Android ObjectAnimator:缩放后动画填充
  10. BitMEX将于3月份分批推出DOT、YFI、UNI等六个币种的双币种永续合约
  11. 进入32位保护模式之路
  12. python语言程序设计王小银_Python语言程序设计答案
  13. 几本适合嵌入式软件工程师阅读的电子入门书
  14. 【深度首发】禾多科技倪凯:作为自动驾驶领域的“拓荒者”,能否成为推动自动驾驶汽车商业落地的第一人?丨Xtecher 封面
  15. Python中参数前面的星号
  16. cubieboard服务器系统,cubieboard 搭建家用服务器
  17. 王者服务器维护杨戬,王者荣耀杨戬-王者荣耀官网网站-腾讯游戏
  18. Canvas流星雨特效
  19. 华芯通服务器芯片将于今年年底前上市
  20. dzzoffice应用如何安装

热门文章

  1. mac 遇到的奇怪问题?
  2. 如何高效学习Oracle
  3. DLLHijack漏洞原理
  4. 转:Mac文件权限操作详细记录
  5. python自带的用于解析HTML的库HtmlParser
  6. MongoDB 查询文档
  7. escape character.
  8. FZU 2108 Mod problem
  9. post-commit hook failed (exit code 255) with no output 解决方案
  10. 自己理解的比特币双重支付