首先给出经验:通常情况下都是将Map的key设为不可变量,如string等,不要用可变量做key。

以下是我的教训!


import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class TestMap {
	public static void main(String[] args) {

		List<Integer> key1 = new LinkedList<>();
		key1.add(1);
		
		 Set<Integer> value1 = new HashSet<>();
		 value1.add(100);
		 
		//分别用List和Set做key和value
		Map<List<Integer>, Set<Integer>> map = new HashMap<>();
		map.put(key1, value1);
		
		System.out.println(map.get(key1));//①
		
		key1.add(2);
		System.out.println(key1);//②
		
		Set<Integer> coll = map.get(key1);//③
		coll.remove(100);

	}
}



在①处能够正常取得value1,输出[100];在②处修改了key1,key1变为[1,2],再次取value1,发现coll为null。经调试,确定map中的内容是{[1, 2]=[100]},为什么取不到东西呢?


看源码:

map的get方法源码如下:

public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }

该方法首先调用了hash(key)方法。



hash(key)的源码如下:

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

因为在这里key的实际类型为LinkedList<Integer>,在我的这个1.8版本的JDK中,LinkedList源码没有重写quals方法和hashCode方法,一直往回推,可以看到其祖先类AbstractList中重写了quals方法和hashCode方法,其中hashCode方法源码如下:


public int hashCode() {
        int hashCode = 1;
        for (E e : this)
            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
        return hashCode;
    }

debug到这里会发现确实得到了一个哈希码,于是hash(key)也就返回了一个int值。接着回到get方法,在里面调用了getNode方法,源码如下:

final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }



debug到这里,发现不满足if的判断条件,因此返回了null。这个方法到底用了什么策略我不想去深究。


按常理,理应能够取得value的,这里却得到null,可能JDK设计人员有特殊的考虑吧,所以千万不要用可变量做键值啊!!!