一,初调HashMap,如何修改JDK的源码进行调试 【深入JDK源码】
起因:故尝试调试下HashMap实现原理,打印出transient Entry<K,V>[] table 变量的变化情况
一,在hashmap中加入打印调试信息
hashmap的实现就是用一个Entry的对象数组Entry中存next形成链,链用于储存key有相同hashcode但key的equas不同的entry,这个网上有很多相关分析;
那么我现在尝试在hashmap这个类中加入监控信息用来展示它的实现原理
打开JDK的源码(基于1.6),并在HashMap类中加入新的方法用于打印调试信息,即HashMap中table对象数组变量的变化
1 public String getTableChageInfor(String messge){
2 StringBuffer tableInfor=new StringBuffer("========");
3 tableInfor.append(messge);
4 tableInfor.append("===start===============");
5 tableInfor.append("\n");
6 tableInfor.append("table.length = ");
7 tableInfor.append(table.length);
8 tableInfor.append("\n");
9 tableInfor.append("table node:");
10 tableInfor.append("\n");
11 for(Entry enty:table){
12 tableInfor.append("entry :{");
13 tableInfor.append(enty);
14 tableInfor.append("}");
15 if(enty!=null)//if enty is null,the table didn't add any value in this position
16 while(enty.next!=null){
17 tableInfor.append("-->{");
18 tableInfor.append(enty.next);
19 tableInfor.append("}");
enty=enty.next;
20 }
21 tableInfor.append("\n");
22 }
23 tableInfor.append("===========end===============");
24 return tableInfor.toString();
25 }
就是迭代打印出table数组对象,和对象的链的所有值,用于监控table值的变化
二,编译并覆盖rt.jar,实现对JDK代码的修改
修改hashmap 类后,重新编译HashMap类,JDK编译器 javac HashMap –Xlint:unchecked
找到生成的hashmap的classes
把classes copy并替换进 JDK 的JRE\jrt.ar包中
然后启动eclipse,运行测试,注意你eclipse中配置的JDK要和你修改的一致
三,简单测试HashMap原理
1,HashMap的初始化
很明确. HashMap 初始化的时候就是长度为16的对象数组 (static final int DEFAULT_INITIAL_CAPACITY = 16;)
2,HashMap的扩容
根据hashmap中的加载因子定义 static final float DEFAULT_LOAD_FACTOR = 0.75f;
那么得出,如果有16*0.75即12个,那么table数组将会翻倍扩容,验证下
可以看到当你put的元素超过了13个时,那么table将会进行扩容,并把原来的值copy进去,其实和ArrayList的实现原理一样,只不过增加了地址定位,链等
3,HashMap的链
当key的hashcode相同,equas不同时,就会根据hashcode计算table索引的对应的链添加元素,所以设计了一个equas相同,但是equas不同的key类
完整代码如下
View Code
package org.benson.test;
public class Key {
private char mapKey;
@Override
public int hashCode() {
return "A".hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Key other = (Key) obj;
if (mapKey != other.mapKey)
return false;
return true;
}
public Key(char mapKey) {
this.mapKey=mapKey;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return String.valueOf(mapKey);
}
}
添加并打印key
package org.benson.test;
import java.util.HashMap;
public class Test4MapTable {
/**@author BensonHe QQ 107966750
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
HashMap hmp=new HashMap();
hmp.put(new Key('A'), "valueA");
hmp.put(new Key('B'), "valueB");
System.out.println(hmp.getTableChageInfor("befor"));
}
}
run,测试结果如下
========befor===start===============
table.length = 16
table node:
entry :{null}
entry :{null}
entry :{null}
entry :{null}
entry :{null}
entry :{B=valueB}-->{A=valueA}
entry :{null}
entry :{null}
entry :{null}
entry :{null}
entry :{null}
entry :{null}
entry :{null}
entry :{null}
entry :{null}
entry :{null}
===========end===============
注:
发现如果根据hashcode计算的index相同,但并非单指hashcode相同,当然hashcode相同计算的index肯定是一样的,具体是在hashmap中实现计算.比如hashcode=18 和 hashcode=33的属于同一个链中
引用个外部图片表示 
便生成了对应的链,而不会新占用table的index
4,原理应用
要求输出valueA,实现key方法
import java.util.HashMap;
public class Test4MapTable {
/**@author BensonHe QQ 107966750
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
HashMap hmp=new HashMap();
hmp.put('A', "valueA");
System.out.println(hmp.get(new Key('A')));
// System.out.println(hmp.getTableChageInfor("befor"));
}
}
其实很简单,覆盖下hashcode和equals方法
如下
View Code
package org.benson.test; public class Key { private char mapKey; @Override public int hashCode() { return String.valueOf(mapKey).hashCode(); } @Override public boolean equals(Object obj) { // if (this == obj) // return true; // if (obj == null) // return false; // if (getClass() != obj.getClass()) // return false; // Key other = (Key) obj; // if (mapKey != other.mapKey) // return false; return obj.equals(mapKey); } public Key(char mapKey) { this.mapKey=mapKey; } @Override public String toString() { // TODO Auto-generated method stub return String.valueOf(mapKey); } }
附上 失败尝试
从JDK源码看到,hashmap的table变量的作用范围是default,即同package可以调用,故尝试继承hashmap 并放在同一个package中
然后ruan,执行失败
抛出
Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.util
找到java.lang.ClassLoader.preDefineClass,打开源码找到了原因:
原来所有以java.开头的package都是被禁止使用的,然而hashmap类又是在java.util中,所以此方法不行
有问题欢迎交流,thanks





View Code



浙公网安备 33010602011771号