所以,我有一个整数数组

Integer[] distances = new Integer[n];

然后,我有了一个PriorityQueue of Nodes,其中的结构包含一个“到”和“距离”,可以按距离排序。
class Node implements Comparable<Node>{
    Integer distance;
    int to;
    Node(int To, Integer Dist){
      to = To;
      distance = Dist;
    }

    @Override
    public int compareTo(Node o) {
      if(this.distance < o.distance)return -1;
      if(this.distance > o.distance) return 1;
      return 0;
    }
  }

我想做的是将节点添加到优先级队列中,如下所示:
PriorityQueue<Node> q = new PriorityQueue<Node>();
q.add(0, distances[0]);

现在,我想更改dist[0]的值,并将其反射(reflect)在PriorityQueue中的Node对象内。 第一个问题:,因为我要在构造函数中传递一个Integer,它将通过引用传递,并且具有类似于使用C++指针执行类似操作的功能:
class Node {
  int* distance;
  int to;
  Node(int To, int* dist){
    distance = dist; to = To;
  }

然后将节点创建为int[] distances = new int[n]; Node nd = new Node(0, &distances[0]);因此,当我更改distances[0]时,我的*nd.distance也将更改。

第二个问题:如果可能,这是一个好习惯吗?或者是否有可能在处置我的优先级队列之前由垃圾收集器处置该阵列?

最佳答案

正如注释中已经指出的那样,您的尝试将失败,因为Integer对象是不可变的。我仍然想为非不可变对象(immutable对象)发布答案,这将指出C++指针的关键区别。

的第一个问题的简短回答:对于“正常”(不可改变)的对象,它具有相似的功能,但并不完全相同。

在Java中,函数接收对象引用的副本。严格来说,这使它可以传递值。以下示例将说明与C++指针的主要区别。

public class Main {
    public static class Test {
        public String text;
        public Test(String text) {
            this.text = text;
        }
        public void doit() {
            System.out.println(text);
        }
    }

    static void reference() {
        Test[] t = {new Test("This is class 0"), new Test("This is class 1")};

        attemptSwitch(t[0], t[1]);
        System.out.println();
        System.out.println("calling t[0].doit() outside attemptSwitch():");
        t[0].doit();
        System.out.println("calling t[1].doit() outside attemptSwitch():");
        t[1].doit();

        manipulate(t[0]);
        manipulate(t[1]);
        System.out.println();
        System.out.println("calling t[0].doit() after manipulate()");
        t[0].doit();
        System.out.println("calling t[1].doit() after manipulate()");
        t[1].doit();
    }

    static void attemptSwitch(Test t0, Test t1) {
        Test tmp = t0;
        t0 = t1;
        t1 = tmp;

        System.out.println("calling t0.doit() from inside attemptSwitch():");
        t0.doit();
        System.out.println("calling t1.doit() from inside attemptSwitch():");
        t1.doit();

    return;
    }

    public static void manipulate(Test t) {
        t.text = "This class has been manipulated!";
    }

}

上面的类将首先创建一个包含两个Test对象的数组。
然后它将尝试在attemptSwitch()中切换这些对象,然后将尝试通过调用text来更改mainpulate()的内容。
输出将如下所示:
calling t0.doit() from inside attemptSwitch():
This is class 1
calling t1.doit() from inside attemptSwitch():
This is class 0

calling t[0].doit() outside attemptSwitch():
This is class 0
calling t[1].doit() outside attemptSwitch():
This is class 1

calling t[0].doit() after manipulate()
This class has been manipulated!
calling t[1].doit() after manipulate()
This class has been manipulated!

如您所见,该切换在attemptSwitch()内成功完成,但是此切换不是持久的。在函数attemptSwitch()之外,引用完全不受影响,并且Test对象未切换。
这是由于事实,即attemptSwitch()仅收到对我们的Test对象的引用的副本。在功能内部仅切换了那些副本。

如对manipulate()的调用所示,可以持久地更改类的内容。在这种情况下,函数仅接收引用的副本并不重要,因为它也指向类存储其内容的相同地址。

至于您的第二个问题,我使用了类似的构造。这种方法可能更容易产生内存泄漏,即,将对象保留在内存中的时间长于所需时间,而不是丢失数据。只要至少有一个引用指向您的对象,就不会收集垃圾-如果该引用不是weak reference或类似的东西。 AFAIK,PriorityQueue使用常规引用。

07-28 02:13
查看更多