通过反射取得hashmap的值
本人最近项目中在遇到个这个情况,需要做动态代理,invoke方法里的参数是object类型,实际参数是hashmap类型,需要从object类型里面取出key value键值对
首先hashmap和object是不能直接强制转换类型的,我采用反射取得数据
为了取得数据,首先得了解下hashmap的结构
在这里只讲点关键点,hashmap里面有个内部类,Node<K,Y>这个就是存放key value 的节点
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
transient Node<K,V>[] table;
可以看出hashmap的值存在属性table数组里面
然后看到node内部类属性有hash值,key,value,指向相同hash值的下一个节点的引用next
因为在hashmap里面key虽然不同,然后有可能经过hash值转换后生成的hash值相同,这个时候,相同的hash值的节点形成一个链表的形式
类似于这个模样,相同的hash值,存储的键值对node节点,以链表组装起来
现在需要将object类参数(实际上是hashmap类型,用父类引用指向子类对象)反射出里面的值
HashMap<String,Object> hashmap=new HashMap<String, Object>();
Class clsHashMap$Node = null;
clsHashMap$Node = Class.forName("java.util.HashMap$Node"); //通过反射得到hashmap里面内部类node
Field[] fields = parameter.getClass().getDeclaredFields();
for(Field field:fields){
field.setAccessible(true);
if(field.getName()=="table"){ //遍历属性,当时table属性时候
Object[] node= (Object[]) field.get(parameter); //得到table属性值
for (Object object : node) { //遍历
if(object!=null){ //有可能table数组有node为空,因为hash值特性
try {
iteration(object, clsHashMap$Node, hashmap); //递归
} catch (NoSuchFieldException | SecurityException e) {
e.printStackTrace();
}
}
}
}
}
private void iteration(Object object,Class clsHashMap$Node,HashMap<String,Object> hashmap) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
Field key = clsHashMap$Node.getDeclaredField("key"); //获取node类里面的key属性
Field value = clsHashMap$Node.getDeclaredField("value"); //获取node类里面value属性
Field next = clsHashMap$Node.getDeclaredField("next"); //获取node类里面next属性
key.setAccessible(true);
value.setAccessible(true);
next.setAccessible(true);
//得到三个属性的属性值
String strkey = key.get(object).toString();
Object objValue = value.get(object);
Object objNext = next.get(object);
//判断next是否为空,不为空则递归
if(objNext==null)
{
hashmap.put(strkey, objValue);
}else{
iteration(objNext, clsHashMap$Node, hashmap);
}
}
最后,我们就讲hashmap里面的值全部反射出来