【问题标题】:How do I create a reference to my object using a variable?如何使用变量创建对我的对象的引用?
【发布时间】:2017-10-31 09:13:34
【问题描述】:

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

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

private int insertValue(int arrayPos, String element){//Checks for collisions with another SNode, and inserts the SNode into the appropriate 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 插入到数组中就好了,这让我相信正在发生的事情是在变量@ 下创建了新的SNode 987654331@,但那个targetNode在实例化后并没有链接到数组位置。我假设它本质上是将第 2 行的数组位置中的数据复制到变量中,然后变成它自己的独立实体。

那么我如何让targetNode 实际引用并影响SNode? (这样,当我向下遍历已经占用的数组空间中的节点链表时,targetNode 指向的是正确的。

注意:为简单起见,我省略了在SNode 中使用setNext() 方法将链表中的前一个节点链接到其下一个节点的行。 p>

【问题讨论】:

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


    【解决方案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>();
    }
    

    【讨论】:

      【解决方案2】:

      这里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));
      

      【讨论】:

      • 是的,但是即使在该程序第一次运行期间数组点为空(因此它跳过了 while 循环,因为targetNode == null)它也不会在那里放置一个新节点。但感谢您指出这可能会造成混淆,我将编辑问题。
      • 不客气。它不起作用的原因与我解释的相同:targetNode = new SNode(element); 创建一个新对象并将其分配给targetNode 变量。但这意味着targetNode 变量不再引用array[arrayPos]。所以对array[arrayPos]没有影响。
      • 是的,这正是我的问题。那么我如何拥有targetNode 参考array[arrayPos]
      • 创建元素并将其添加到数组中:array[arrayPos] = new SNode(element) 然后将其存储在变量中:targetNode = array[arrayPos]
      • 好的,这适用于第一次迭代。但是,如果稍后尝试将另一个项目添加到该索引中,我怎么知道在array[arrayPos] 上使用.getNext() 方法多少次?因为据程序所知,在第一个节点之后,链表中可能有一个或两个或十个节点。
      【解决方案3】:

      你有一个误解。变量和数组元素都不包含对象。它们持有对对象的引用。此外,变量和数组位置本身不是对象,因此在 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,则直接分配给数组元素)。

      【讨论】:

      • 啊哈!好的,所以 initial 时间我需要一个if 语句来检查数组索引是否为空。如果是我需要直接编辑数组索引以添加新的SNode. 但是之后我可以使用targetNode 指向它之后的链表对象,它会正常工作。谢谢,这完美解决了我的问题!
      • 您可能还想在创建时使用虚拟 SNode 初始化数组,这样您就不需要一直检查它是否是第一个节点。查看您的其他代码,该虚拟节点实际上可能是一个子类,它还具有指向列表中当前最后一个元素的指针,因此您无需遍历列表即可找到最后一个。
      猜你喜欢
      • 2016-06-04
      • 1970-01-01
      • 2020-07-10
      • 1970-01-01
      • 1970-01-01
      • 2020-03-17
      • 2012-10-10
      • 1970-01-01
      • 2012-06-28
      相关资源
      最近更新 更多