如何使用变量创建对象的引用?

时间:2017-05-30 19:00:11

标签: java variables pass-by-reference pass-by-value

所以我有一个充满节点的数组,称为“SNode s”(它们是我自己创建的类。它们实际上只是一个基本节点,它包含一个String和一个指向下一个节点的指针)

我有一个名为insertValue()的方法,它接受你想要输入值的索引和你希望SNode包含的字符串。但是,如果传递的索引中已包含SNode,我希望新值成为SNode的“下一个”节点(实质上是在每个索引空间中创建一个链接的节点列表)。

private int insertValue(int arrayPos, String element){//Checks for collisions with another SNode, and inserts the SNode into the apppropriate spot in the array
 SNode targetNode = array[arrayPos];//What I want to be a reference to the node at the desired position in the array

 while (targetNode != null){//If an SNode already exists in that position, keeps iterating down until it gets to a non-existant SNode.
  targetNode = targetNode.getNext();//getNext is a method in my SNode that just returns a reference to that SNode's "nextNode" variable.
 }
  targetNode = new SNode(element);
  return arrayPos;
}//end insertValue

我的问题是,在运行此方法后,它不会在所需的数组位置创建一个新节点,即使是在数组点为空时第一次运行。

如果我将targetNode = new SNode(element);更改为array[arrayPos] = new SNode(element);,它显然会将SNode插入数组中,这样就可以让我相信正在发生的事情是新的{{1}正在变量SNode下创建,但targetNode在实例化后没有链接到数组位置。我假设它实际上是将数据从第2行的数组位置复制到变量中,但随后变成了自己独立的实体。

那么我如何targetNode实际引用并影响targetNode? (当我在已占用的数组空间中遍历链接的节点列表时,targetNode指向正确的节点。

注意:为了简单起见,我遗漏了SNode中使用setNext()方法的行,将链接列表中的上一个节点链接到下一个节点之一。

3 个答案:

答案 0 :(得分:1)

此处targetNode是指array[arrayPos]引用的对象。

 SNode targetNode = array[arrayPos];//What I want to be a reference to the node at the desired position in the array

但是当你写下来的时候:

targetNode = targetNode.getNext();//getNext is a method in my SNode that just 

您更改了targetNode变量引用的对象。现在它引用它的下一个节点。

然后当你这样做:

 targetNode = new SNode(element);

您创建一个新对象并将其分配给targetNode变量,但最终它永远不会与现有节点相关联。

它不会为下一个节点分配一个新节点 要做到这一点你可以写:

targetNode.setNext(new SNode(element));

答案 1 :(得分:1)

你有一种误解。变量和数组元素都不包含对象。他们将引用保存到对象。此外,变量和数组位置本身不是对象,因此Java中没有办法引用它们。最接近的是获得变量或数组位置包含的值的副本(对象的引用)。

因此,这......

SNode targetNode = array[arrayPos];

...将array[arrayPos]的值复制到变量targetNode中。如果该值为非null,则后面的变量引用数组元素所执行的相同对象,但不复制对象本身。在那种情况下,当您使用

走链表时,这很好,而且正是您想要的
targetNode = targetNode.getNext();

,您不想修改array[arrayPos]或任何节点' next引用,因为那样你就会丢失链表的元素。

但你不能两种方式。当您最终找到新SNode的位置并执行此操作时......

targetNode = new SNode(element);

...它不会记录您最近复制SNode的值的新targetNode的引用。它只是将引用放在targetNode

您要做的是找到最后一个当前节点(如果有),并分配给它的next引用(或者直接指向数组元素,如果它最初是null)。

答案 2 :(得分:1)

正如其他答案所示,使用正常的解决方案,您将测试它是否是数组中的第一个元素,并在这种情况下做一些不同的事情。即如果是第一个就直接在数组中设置元素,如果不是则遍历列表。

一种有效的替代方法是在数组中使用一个虚拟元素,该元素仅用于其下一个字段,并在创建时使用虚拟元素初始化数组。在你的情况下,你甚至可以给虚拟元素一个额外的 last 字段,这将不需要遍历列表来查找最后一个元素。类似于以下内容:

interface SNodeRef {
    SNode getNext();
    void setNext(SNode node);
}

class FirstNode implements SNodeRef {
    SNodeRef getLast();
    void setLast(SNodeRef);
    ....
    FirstNode() { setLast(this); }
}

class SNode implements SNodeRef { ... }

private int insertValue(int arrayPos, String element) {
    SNode newNode = new SNode(element);
    FirstNodeRef ref = array[arrayPos];
    ref.getLast().setNext(newNode);
    ref.setLast(newNode);
}

FirstNode[] array = new FirstNode[10];
for (int i = 0; i < array.length; i++) {
    array[i] = new FirstNode();
}

或者,由于它是您使用的链表,您可以简单地使用预定义的 LinkedList 数据结构:

private int insertValue(int arrayPos, String element) {
    array[arrayPos].addLast(element);
}

var array = new LinkedList<String>[10];
for (int i = 0; i < array.length; i++) {
    array[i] = new LinkedList<String>();
}