Java Class 尽管限制了访问,但变量并不是不可变的

Java Class variables are not immutable despite restricting access

我有一个我写的矩阵对象。我希望矩阵作为对象的属性是不可变的,用多维数组实现。作为 this.matrix。当我调用矩阵方法时。确保 return 一个新的矩阵对象,传入创建对象的数组应该被深度复制。

我在 codewars 中的一项测试失败,其中预期的双精度值与我调用 toArray() 方法时给出的值不同。但由于测试代码受限,我不知道任何mroe信息。

任何人都可以在下面的代码中看到我是否在其中创建了一个矩阵,其 this.matrix 属性可以从对象本身外部修改?

我尝试在构造函数中使用 Arrays.copyOf 来确保为 this.matrix 属性创建新对象。我已经确保 return 每个方法都有一个新的 Matrix 对象。所以我真的不明白 'this.matrix' 实例变量还能在哪里被无意中修改。

    import java.util.Arrays;

@SuppressWarnings("WeakerAccess")
public class Matrix {

    private double[][] matrix;
    private int  rows;
    private int columns;
    //constructor for the already sorted array

    Matrix(double[][] elements) {

        if (elements == null) {
            throw new IllegalArgumentException("Elements cannot be null");
        }
        int columns = elements[0].length;
        for(double[] element: elements){
            if(element == null){
                throw new IllegalArgumentException("Element of 2D Array cannot be null");
            }
            if(element.length != columns){
                throw new IllegalArgumentException("Array rows are not of equal length");
            }

        }

        this.matrix = elements;
        this.rows = this.matrix.length;
        this.columns = columns;


    }

    /// given row_length, row_column
    /// given list of elements
     Matrix(int rows, int columns, double... elements) {
        // remember double   ... elements means varargs

        if(elements == null){
            throw new IllegalArgumentException("Elements cannot be null");
        }

        if (elements.length != rows * columns) {
            throw new IllegalArgumentException("Illegal number of rows and columns for elements given");
        }
        this.rows = rows;
        this.columns = columns;
        this.matrix = new double[this.rows][this.columns];
        for(int i = 0; i<this.rows; i++){
//            System.arraycopy(elements, i*columns, this.matrix[i], 0, columns);
              double[] row = Arrays.copyOfRange(elements, i*columns, (i+1) * columns);
              this.matrix[i] = Arrays.copyOf(row,columns);
        }

    }

    public double[][] toArray() {
        return this.matrix;
        ///prints out the array to string
    }

    public Matrix multiply(double scalar){

        // this will just multiply the matrix with the scalar
        double[][] result = new double[this.rows][this.columns];

        for(int i = 0; i < this.matrix.length; i++){
            for(int j = 0; j < this.matrix[0].length; j++){

                result[i][j] = this.matrix[i][j] * scalar;

            }
        }
        return new Matrix(result);
    }

    public Matrix multiply(Matrix right){

        double[][] right_mat = right.toArray();
        //assert that left n = right m
        if(this.columns != right.rows){
            throw new IllegalArgumentException("Left matrix columns is not equal to Right matrix rows");
        }
        double[][] result = new double[this.rows][right.columns];


        //loop through twice and incrememnt the additions

        for(int m = 0; m < this.rows; m++){

            for(int k = 0; k < right.columns;k++){

                for(int n = 0; n < right.rows; n++){

                    result[m][k] += this.matrix[m][n] * right_mat[n][k];
                }
            }
        }

        return new Matrix(result);
    }

    public Matrix transpose(){
        double[][] result = new double[this.columns][this.rows];

        for(int i = 0; i < this.matrix[0].length; i++){

            final int column = i;
            // new_row should be column of existing
            double[] new_row = Arrays.stream(this.matrix).mapToDouble(doubles -> doubles[column]).toArray();
            result[i] = new_row;

        }
        return new Matrix(result);
    }
    public Matrix add(Matrix b){
        ///takes in Matrix adds to this one and
        ///returns the resulting Matrix
        if(this.columns != b.columns || this.rows != b.rows){
            throw new IllegalArgumentException("Matrices are not the same shape");
        }
        double[][] b_matr = b.toArray();
        double[][] result = new double[this.rows][this.columns];

        ///Matrix needs to have the same number of rows and columns

        for(int i= 0; i < this.rows; i++){
            for(int j = 0; j < this.columns; j++){
                result[i][j] = this.matrix[i][j] + b_matr[i][j];
            }
        }
        return new Matrix(result);
    }
}

首先,您的构造函数 Matrix(double[][] array) 不会对元素进行深度复制。 其次,您的 toArray() 方法应该 return this.matrix 的深拷贝而不是 属性 本身。

你可以像这样深拷贝数组

double[][] copy = new double[this.matrix.length][];
for (int i = 0; i < copy.length; ++i) {
  copy[i] = new double[this.matrix[i].length];
  for (int j = 0; j < copy[i].length; ++j) {
    copy[i][j] = this.matrix[i][j];
  }
}