关于java中的HashMap实现
我试图对hashmap进行研究,并得出以下分析: Q1你们能给我一个简单的映射吗?在这里你们可以展示这个过程。这个过程是如何使用这个公式详细计算给定键的hashcode。计算位置hash%(arraylelength-1))元素应该放在哪里(bucket number),假设我有这个hashMap关于java中的HashMap实现,java,collections,hashmap,Java,Collections,Hashmap,我试图对hashmap进行研究,并得出以下分析: Q1你们能给我一个简单的映射吗?在这里你们可以展示这个过程。这个过程是如何使用这个公式详细计算给定键的hashcode。计算位置hash%(arraylelength-1))元素应该放在哪里(bucket number),假设我有这个hashMap HashMap map=new HashMap();//HashMap key random order. map.put("Amit","Java"); map
HashMap map=new HashMap();//HashMap key random order.
map.put("Amit","Java");
map.put("Saral","J2EE");
Q2有时可能发生两个不同对象的哈希代码相同的情况。在这种情况下,2个对象将保存在一个bucket中,并显示为LinkedList。入口点是最近添加的对象。此对象引用另一个对象,其中包含下一个字段和一个字段。最后一个条目引用null。你们能给我看一个真实的例子吗
由于钻头抖动,“Amit”将分配到第10个铲斗。如果没有比特抖动,它将进入第7个桶,因为2044535&15=7。如何做到这一点请详细解释整个计算过程
快照已更新
另一个图像是
Q1:查看hashCode()
字符串对象的方法实现
问题2:创建一个简单的类,并将其hashCode()
方法实现为return1
。这意味着每个对象和该类将具有相同的hashCode,因此将保存在HashMap中的同一个bucket中
如何使用
这个公式
在String
的情况下,这是通过String#hashCode()计算的代码>其实现方式如下:
public int hashCode() {
int h = hash;
int len = count;
if (h == 0 && len > 0) {
int off = offset;
char val[] = value;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
在这个实现中需要注意的一件有趣的事情是String
实际上缓存了它的哈希代码。它可以做到这一点,因为String
是不可变的
如果我计算字符串
“Amit”的hashcode,它将生成以下整数:
System.out.println("Amit".hashCode());
> 2044535
让我们完成一个简单的地图放置,但是首先我们必须确定地图是如何构建的。
JavaHashMap
最有趣的事实是它总是有2^n个bucket。因此,如果您调用它,默认的存储桶数是16,这显然是2^4
在此映射上执行put操作,它将首先获取密钥的哈希代码。在这个哈希代码上会发生一些奇特的位抖动,以确保糟糕的哈希函数(尤其是那些在低位没有差异的函数)不会“重载”单个bucket
实际负责将密钥分发到存储桶的真正功能如下:
h & (length-1); // length is the current number of buckets, h the hashcode of the key
这只适用于两个存储桶大小的幂,因为它使用&将密钥映射到存储桶,而不是模
由于钻头抖动,“Amit”将分配到第10个铲斗。如果没有比特抖动,它将进入第7个桶,因为2044535&15=7
现在我们有了它的索引,我们就可以找到桶了。如果bucket包含元素,我们必须对它们进行迭代,并在找到元素时替换一个相等的条目。
如果在链表中找不到任何项目,我们只会将其添加到链表的开头
HashMap
中的下一个重要内容是调整大小,因此,如果映射的实际大小超过阈值(由当前存储桶数和加载因子决定,在我们的示例中为16*0.75=12),它将调整备份数组的大小。
Resize始终是当前存储桶数的2倍,保证为2的幂,以不破坏查找存储桶的函数
由于存储桶的数量发生变化,我们必须重新刷新表中的所有当前条目。
这是非常昂贵的,因此如果您知道有多少项,您应该使用该计数初始化哈希映射
,这样它就不必调整整个时间的大小。了解哈希代码有两个基本要求:
当为给定对象重新计算哈希代码时(该对象没有以改变其标识的方式进行内部更改),它必须生成与上一次计算相同的值。类似地,两个“相同”的对象必须生成相同的哈希代码
当为两个不同的对象计算哈希代码时(从其内部内容的角度来看,这两个对象并不“相同”),两个哈希代码很可能不同
这些目标是如何实现的,是从事这类工作的数学迷们非常感兴趣的主题,但了解细节对于理解哈希表的工作方式并不重要。import java.util.Arrays;
import java.util.Arrays;
public class Test2 {
public static void main(String[] args) {
Map<Integer, String> map = new Map<Integer, String>();
map.put(1, "A");
map.put(2, "B");
map.put(3, "C");
map.put(4, "D");
map.put(5, "E");
System.out.println("Iterate");
for (int i = 0; i < map.size(); i++) {
System.out.println(map.values()[i].getKey() + " : " + map.values()[i].getValue());
}
System.out.println("Get-> 3");
System.out.println(map.get(3));
System.out.println("Delete-> 3");
map.delete(3);
System.out.println("Iterate again");
for (int i = 0; i < map.size(); i++) {
System.out.println(map.values()[i].getKey() + " : " + map.values()[i].getValue());
}
}
}
class Map<K, V> {
private int size;
private Entry<K, V>[] entries = new Entry[16];
public void put(K key, V value) {
boolean flag = true;
for (int i = 0; i < size; i++) {
if (entries[i].getKey().equals(key)) {
entries[i].setValue(value);
flag = false;
break;
}
}
if (flag) {
this.ensureCapacity();
entries[size++] = new Entry<K, V>(key, value);
}
}
public V get(K key) {
V value = null;
for (int i = 0; i < size; i++) {
if (entries[i].getKey().equals(key)) {
value = entries[i].getValue();
break;
}
}
return value;
}
public boolean delete(K key) {
boolean flag = false;
Entry<K, V>[] entry = new Entry[size];
int j = 0;
int total = size;
for (int i = 0; i < total; i++) {
if (!entries[i].getKey().equals(key)) {
entry[j++] = entries[i];
} else {
flag = true;
size--;
}
}
entries = flag ? entry : entries;
return flag;
}
public int size() {
return size;
}
public Entry<K, V>[] values() {
return entries;
}
private void ensureCapacity() {
if (size == entries.length) {
entries = Arrays.copyOf(entries, size * 2);
}
}
@SuppressWarnings("hiding")
public class Entry<K, V> {
private K key;
private V value;
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
public Entry(K key, V value) {
super();
this.key = key;
this.value = value;
}
}
}
公共类Test2{
公共静态void main(字符串[]args){
Map Map=newmap();
地图.付诸表决(1,“A”);
图.put(2,“B”);
图.put(3,“C”);
图.put(4,“D”);
地图.put(5,“E”);
System.out.println(“迭代”);
对于(int i=0;i3”);
System.out.println(map.get(3));
System.out.println(“删除->3”);
删除(3);
System.out.println(“再次迭代”);
对于(int i=0;iimport java.util.Arrays;
public class Test2 {
public static void main(String[] args) {
Map<Integer, String> map = new Map<Integer, String>();
map.put(1, "A");
map.put(2, "B");
map.put(3, "C");
map.put(4, "D");
map.put(5, "E");
System.out.println("Iterate");
for (int i = 0; i < map.size(); i++) {
System.out.println(map.values()[i].getKey() + " : " + map.values()[i].getValue());
}
System.out.println("Get-> 3");
System.out.println(map.get(3));
System.out.println("Delete-> 3");
map.delete(3);
System.out.println("Iterate again");
for (int i = 0; i < map.size(); i++) {
System.out.println(map.values()[i].getKey() + " : " + map.values()[i].getValue());
}
}
}
class Map<K, V> {
private int size;
private Entry<K, V>[] entries = new Entry[16];
public void put(K key, V value) {
boolean flag = true;
for (int i = 0; i < size; i++) {
if (entries[i].getKey().equals(key)) {
entries[i].setValue(value);
flag = false;
break;
}
}
if (flag) {
this.ensureCapacity();
entries[size++] = new Entry<K, V>(key, value);
}
}
public V get(K key) {
V value = null;
for (int i = 0; i < size; i++) {
if (entries[i].getKey().equals(key)) {
value = entries[i].getValue();
break;
}
}
return value;
}
public boolean delete(K key) {
boolean flag = false;
Entry<K, V>[] entry = new Entry[size];
int j = 0;
int total = size;
for (int i = 0; i < total; i++) {
if (!entries[i].getKey().equals(key)) {
entry[j++] = entries[i];
} else {
flag = true;
size--;
}
}
entries = flag ? entry : entries;
return flag;
}
public int size() {
return size;
}
public Entry<K, V>[] values() {
return entries;
}
private void ensureCapacity() {
if (size == entries.length) {
entries = Arrays.copyOf(entries, size * 2);
}
}
@SuppressWarnings("hiding")
public class Entry<K, V> {
private K key;
private V value;
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
public Entry(K key, V value) {
super();
this.key = key;
this.value = value;
}
}
}