读书的时候老实说,当我们调用HashMap的put方法的时候, 同样key的值会被覆盖掉
但是 最近闲来无事研究下HashMap发现其实并不是这回事,JDK1.7以及之前对应的那个存储区域会有个LinkedList,JDK8之后换成了红黑树。 当我们put相同key的时候,会把最新的值放在那个List的第一个, 也就是说我们get到的值会是最新put进去的, 也就是老师说的“覆盖掉了”
那么这里我有个问题想请教各位大神了,既然HashMap是有这个存储机制的,那么我想请教一下, 我用什么方式可以get到这个List或者tree呢?  我看了下API, 官方并没有提供获取的方法.PS: 虽然没有实用性, 但是对那些喜欢研究原理和源代码的朋友一定是有帮助的, 所以请知道的各位朋友们和大神们踊跃发言.

解决方案 »

  1.   

    特意去看了一下 jdk1.7 的 HashMap 的源码,put 方法如下:
        public V put(K key, V value) {
            if (table == EMPTY_TABLE) {
                inflateTable(threshold);
            }
            if (key == null)
                return putForNullKey(value);
            int hash = hash(key);
            int i = indexFor(hash, table.length);
            for (Entry<K,V> e = table[i]; e != null; e = e.next) {
                Object k;
                if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                    V oldValue = e.value;
                    e.value = value;
                    e.recordAccess(this);
                    return oldValue;
                }
            }        modCount++;
            addEntry(hash, key, value, i);
            return null;
        }
    如果 key 是同一个对象,或者 equals (默认也是同一个对象为 true) 一致的话,才会覆盖。
    但是是纯粹的指针性质的覆盖,没有看到楼主所说的放进一个 LinkedList (current 的是最新的、next 指向覆盖过的历史)  的逻辑断点跟踪查看 HashMap 对象的内部结构值,也只看到了哈希值相同时的 LinkedList,没有找到楼主所说的装载覆盖历史的 LinkedList。以上红色部分,向楼主请教一下,能否解释一下?
      

  2.   

    JDK1.7以及之前对应的那个存储区域会有个LinkedList表示没听懂什么是存储区域。HashMap中存储的数据对象是 HashMap$Entry<K,V>,也不是LinkedList。
      

  3.   

    应该不能叫LinkedList,毕竟java有个集合的实现类叫这个,那个只是链表,而且同样的key是会被替换的,不是你所说的放在第一位,个人觉得你应该没看懂代码
      

  4.   

    这个所谓的List等是为了应对冲突,也就是不同的key,但是他们的hash刚好相同,那么就不能直接覆盖,而是通过一个list或tree来维护所有的数据,这样查找的时候,可以根据key,找到它正确对应的value。而如果key相同,那么就是覆盖
      

  5.   

    HashMap<String, String> h = new HashMap<>();
    h.put("1", "ok");
    h.put("2", "No");
    //当我们put相同key的时候,会把最新的值放在那个List的第一个,我用什么方式可以get到这个List或者tree呢?
    Set<String> keySet = h.keySet();//这个就是楼主要的list或tree
    for(String s:keySet){
    System.out.println(s+"=="+h.get(s));
    }
    //如果不是 那么你所表达的无人能解了
      

  6.   

    看了一下,拿不到,如果能拿到的话,那就可以改变HashMap的行为了,显然设计者是不允许这样做的。
      

  7.   

    应该是最新的值放到每个数组槽中的链表的第一个位置,因为hashmap认为后进来的比先进来的访问的概率大,所以为了遍历的时候效率高,将后进来的放到先进来的前面
      

  8.   

    根据楼主的描述,楼主的意思是不是要获取table这个数组?因为table就是放置相同hash值的List。    public static void hashmap()
            throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
            HashMap<String, String> map = new HashMap<>();
            map.put("1234", "1234");
            map.put("2345", "2345");
            Field table = map.getClass().getDeclaredField("table");
            table.setAccessible(true);
            Object value = table.get(map);        Class c2 = Class.forName("java.util.HashMap$Entry");        for(int i = 0; i < Array.getLength(value); i ++) {
                Object v = Array.get(value, i);
                if(v != null) {
                    Entry<String, String> c = (Entry<String, String>) v;
                    Field next = c2.getDeclaredField("next");
                    next.setAccessible(true);
    //                Object n = next.get(v);
                    for(; c != null; c = (Entry<String, String>)next.get(c)) {
                        System.out.println(c.getKey());
                        System.out.println(c.getValue());
                    }
                }
            }
        }写了一段简陋的代码,不知道是否符合楼主的要求。