通过引用操作对象

Manipulating an object through its reference

我正在编写 HashTable 的实现作为我课程中的练习,我正在使用一个 LinkedLists 数组,每个 LinkedLists 包含一个键值对(元素)来实现这一点。 我不想写 list[key % size] 来引用我正在操作的元素,而是想写 currentNode.

此代码抛出 NullPointerException:

public void put(int key, T value) {
        var currentNode = list[key % size];

        if(currentNode == null)
            list[key % size] = new LinkedList<>();
        else
            for(var item : currentNode)
                if (item.value == value)
                    return;
        currentNode.add(new Element<>(key, value));
    }

我知道错误发生是因为 currentNode 持有对空对象的引用,我的问题是为什么 currentNode 在更新 list[key % size] 时没有更新?

...my question is why isn't currentNode updated when list[key % size] is updated?

因为 currentNode 不是 list[key % size] 的别名。 list 数组中的元素和 currentNode 中的每个元素都是 单独的 变量,在执行此语句后,它们都包含相同的引用:

var currentNode = list[key % size];

当执行这些语句并且谓词计算为 true:

if(currentNode == null)
            list[key % size] = new LinkedList<>();

数组位置 [key % size] 的变量将包含对新创建的链表实例的引用。但是 currentNode 仍将包含 null,因为它的引用没有被赋值更新。

要强制这两个变量对同一实例具有相同的引用,您需要执行如下操作:

if(currentNode == null)
            currentNode = new LinkedList<>();
            list[key % size] = currentNode;
:
:

除了性能之外,% 运算符是一个有点昂贵的操作。如果您希望表上的 put() 操作经常导致新的列表条目,那么将操作提升到方法开头的赋值可能会更高效(并且绝对更具可读性):

public void put(int key, T value) {
        int index = key % size;
        var currentNode = list[index];

然后将所有 key % size 替换为 index

也许这个架构会对你有所帮助:

  Reference          Heap Object

时刻 1:当前节点 -> 对象 1(空)

  list[key % size]     ->

时刻 2:当前节点 -> 对象 1(空)

  list[key % size]     ->   object 2(new LinkedList<>();)