Java 对两个向量求和的参考可变性

References Mutability in Java summing two vectors

我是 Java 的新手,我正在学习 class,但是在其中一个练习中,我在比较我的答案与老师的答案时产生了疑问。

假设我有一个 class 将多项式的系数保存为属性,我现在想添加两个多项式。

在老师的解决方案(方法add_1)中,他复制了两个数组的系数求和,但是据我所知,到目前为止,双精度数是不可变的,所以我认为我不需要使用副本,但只能直接使用地址(方法 add_2)。我已经测试了我在数组中的值没有发生变化,但是我想确认我的理解。

public class Polynomial {

    // coefficient at index k belongs to term x^k
    // consistency: array is always present and contains at least one number (which
    // may be zero)
    private double[] coefficients;

    // --------------------- constructors
    // ----------------------------------------------

    // constructor: zero polynomial
    public Polynomial() {
        coefficients = new double[1];
        coefficients[0] = 0;
    }

    public static Polynomial add_1(Polynomial f, Polynomial g) {        // Option 1
        double[] f_array = f.getCoefficients();//Do I need this copy?
        double[] g_array = f.getCoefficients();//Do I need this copy?
        int n = Math.max(f_array.length, g_array.length); // new array needs to be this long

        double[] target = new double[n];
        // fastest way to do it without if-statements:
        for (int k = 0; k < n; k = k + 1) {
            target[k] = 0;//Zero vector array
        }
        for (int k = 0; k < f_array.length; k = k + 1) {
            target[k] = target[k] + f_array[k];
        }
        for (int k = 0; k < g_array.length; k = k + 1) {
            target[k] = target[k] + g_array[k];
        }

        // Turn array into an object
        Polynomial p = new Polynomial();
        p.setCoefficients(target);
        return p;
    }

    public static Polynomial add_2(Polynomial f, Polynomial g) {        // Option 2
        int n = Math.max(f_array.length, g_array.length); // new array needs to be this long

        double[] target = new double[n];
        // fastest way to do it without if-statements:
        for (int k = 0; k < n; k = k + 1) {
            target[k] = 0;//Zero vector array
        }
        for (int k = 0; k < f.coefficients.length; k = k + 1) {
            target[k] = target[k] + f.coefficients[k];
        }
        for (int k = 0; k < g.coefficients.length; k = k + 1) {
            target[k] = target[k] + g.coefficients[k];
        }

        // Turn array into an object
        Polynomial p = new Polynomial();
        p.setCoefficients(target);
        return p;
    }


    // --------------------- setter / getter methods
    // -----------------------------------

    // setter for coefficients, creates a copy(!) of coefficients and stores it
    public void setCoefficients(double[] coefficients) {
        this.coefficients = new double[coefficients.length];
        for (int k = 0; k < coefficients.length; k = k + 1) {
            this.coefficients[k] = coefficients[k];
        }
    }

    // getter for coefficients, returns a copy(!) of the polynomials coefficients
    public double[] getCoefficients() {
        double[] copy = new double[coefficients.length];
        for (int k = 0; k < coefficients.length; k = k + 1) {
            copy[k] = coefficients[k];
        }
        return copy;
    }

}
  1. 我的方法 add_2 是否受到保护以防止突变,或者我是否有任何理由应该使用副本?

非常感谢

double[] f_array = f.getCoefficients();//Do I need this copy?

这掩盖了对 java 的误解。

f.getCoefficients() 不是 return 双数组。那是不可能的; java 只能 return 基元和引用。它return是双数组的引用。

这里没有复制数组。 java 隐式制作的唯一副本是引用和基元;任何其他复制都是您必须明确使用的内容,例如copy()clone()Arrays.copyOf 调用。您在这里所做的只是复制了一份 参考文献,这无关紧要。 f.getCoefficients() 已经 return 引用的副本。

让我试着用一个例子来解释:

class Example {
    double[] array = new double[10];

    public static void main(String[] args) {
        Example ex = new Example();
        double[] arr = ex.array;
        arr[0] = 1;
        System.out.println(arr[0]);
        System.out.println(ex.array[0]);
        ex.array[0] = 2;
        System.out.println(arr[0]);
        System.out.println(ex.array[0]);
        arr = new double[20];
        arr[0] = 20;
        System.out.println(arr[0]);
        System.out.println(ex.array[0]);
    }
}

> 1
> 1
> 2
> 2
> 20
> 2

最初只有一个数组,ex.arrayarr都是指向这个数组的引用。 arr[0] = 正在取消引用引用并对您在那里找到的内容进行操作,因此,虽然 arrex.array 是副本,但它是同一引用的副本,就像我做一张藏宝图副本交给你,如果你跟着你的地图,挖下去,偷走宝藏,然后我跟着我的副本,我发现宝藏不见了 - 所以它在这里:arr[0] = 1 影响唯一数组,因此打印 ex.array[0[] 也显示 1.

后来用arr = new double[20]我们先新建一个对象(new double[20]),然后把这个新建对象的引用赋值给arr,对ex.array。因此,现在,就好像你有一张与我的 ex.array 藏宝图完全不同的藏宝图。因此,当你按照你的地图向下挖掘并在框中放一个 20 时,如果我按照我的地图,我 不会 看到它,因此为什么最后 2行打印 201,而不是 2020.