LinkedHashMap是如何在内部工作的?

8

我读到了LinkedHashMap的相关描述,虽然很有趣,但我不理解它在底层是如何工作的。顺便说一句,我知道Java中HashMap的底层实现。
于是我查看了源代码,但仍然无法理解它的工作原理。也许我在面向对象编程方面没有掌握某些基础知识,请耐心指点。
总结起来,让我困惑的部分如下:
LinkedHashMap将所有调用委托给其父类HashMap。内部重写了HashMap.Entry以实现各种recordAccessrecordRemoval方法,这些方法似乎实现了LinkedHashMap的逻辑。
但实际上,Entries位于基类的表格中,即HashMap,后者实例化了一个HashMap.Entry表格,而不是LinkedHashMap.Entry表格。
所以我无法弄清楚各种recordAccessrecordRemove等方法是如何被调用的。
请问有人可以帮助我理解这里发生了什么吗?
我的想法是,LinkedHashedMap.Entry以某种方式是由HashMap创建的表格类型?但是如何实现的呢?

更新:
我的问题是recordAccess是如何被调用的。我使用一个派生版本的HashMap进行实验失败了,原因是Shengyuan Lu (+1) - 我的错。

更新:
我尝试的以下内容与LinkedHashMap所做的相同(我认为):

package delete;  

public class Base<T> {  

    Entry<T>[] table;  
    int idx = 0;  
    @SuppressWarnings("unchecked")  
    public Base(){  
        System.out.println("In base");  
        table = new Entry[10];  
    }

    public void add(T x){  
        table[idx] = new Entry(x);  
        table[idx].doSomething();  
    }  

    static class Entry<T>{  
        T value;  

        Entry(T x){  
            this.value = x;  
            System.out.println("Entry::Base");  
        }

        void doSomething(){  
            System.out.println("In Entry base, doing something");  
        }  
    }  

}  




public class Derived<T> extends Base<T> {  

    static class Entry<T> extends Base.Entry<T>{  

        Entry(T x) {  
            super(x);  
            System.out.println("In Entry derived");  
        }  

        int val;  

        @Override  
        void doSomething() {  
            System.out.println("In Entry derived doing something really smart!");  
        }       
    }  

    /**
     * @param args
     */
    public static void main(String[] args) {  

        Base<String> b = new Derived<String>();  
        b.add("Test string");  

    }  

}  

但它打印出:
In base  
Entry::Base     
In Entry base, doing something    

因此,派生的Entry从未被调用。
我的例子有什么不同吗?我不明白这对于LinkedHashMap是如何工作的。

受保护的还是包级私有? - assylias
2
阅读此链接以了解为什么LinkedHashMap被定义为继承HashMap并实现Map。 - Pshemo
@Pshemo:谢谢你。在你提供的链接解释之后,我更新了原始帖子。现在我只需要帮助回答我的核心问题。 - Cratylus
2个回答

4
如果你将MyLinkedHashMap定义在java.util包下,它会编译通过;)
因为HashMap.HashEntry是包可见性。
另外:
我认为让你困惑的主要问题是LinkedHashMap.EntryHashMap.Entry。关键是LinkedHashMap.Entry是一个HashMap.Entry。实际上HashMap.table在LinkedHashMap中存储LinkedHashMap.Entry
关于recordAccessrecordRemoval,它们都覆盖了HashMap.Entry版本。你可以在LinkedHashMap和HashMap中找到引用。
合并评论:你的示例代码与LinkedHashMap的实现不同。请参考LinkedHashMap.addEntry()

但是怎么做呢?HashMap使用table = new Entry[DEFAULT_INITIAL_CAPACITY]; - Cratylus
@user384706 请考虑以下代码:Object[] table=new Object[1]; table[0] = "我是 Object 的子类"; - 卢声远 Shengyuan Lu

2

在这里,Ctrl+F非常有用,特别是当它允许您同时搜索多个文件时。通过映射的putget方法调用访问/创建的条目上的recordAccess。(调用在HashMap.putHashMap.putForNullKeyLinkedHashMap.get中。)只有在使用带有布尔参数的LinkedHashMap的构造函数且传递true时才相关。这样做的影响是,每当您触摸(touch)地图时,被触摸的条目将移动到内部链接列表的最前面。

引用文档:

提供了一个特殊的构造函数,用于创建一个链式哈希映射,其迭代顺序是其条目最后访问的顺序,从最近访问的到最近访问的(访问顺序)。这种类型的映射非常适合构建LRU缓存。调用put或get方法会导致对相应条目的访问(假设在调用完成后存在该条目)。putAll方法为指定映射中的每个映射生成一个条目访问,并按照指定映射的键值映射由指定映射的条目集迭代器提供的顺序进行。没有其他方法生成条目访问。特别是,集合视图上的操作不会影响后备映射的迭代顺序。

可以覆盖removeEldestEntry(Map.Entry)方法,在添加新映射到映射时自动实施删除陈旧映射的策略。

同样,recordRemovalHashMap.removeEntryForKeyHashMap.removeMapping中调用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接