尽管限制访问,Java 类变量并不是不可变的

标签 java matrix immutability public-method

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

我在 codewars 中的一项测试失败了,其中预期的 double 值与我调用 toArray() 方法时给出的值不同。但我不知道任何mroe信息,因为测试代码受到限制。

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

我尝试在构造函数中使用Arrays.copyOf来确保为this.matrix属性创建新对象。我确保为每个方法返回一个新的 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() 方法应该返回 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];
  }
}

关于尽管限制访问,Java 类变量并不是不可变的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54027678/

相关文章:

c - c编程中具有函数递归的nxn矩阵的行列式

java - 向右旋转二维矩阵

java - 不可变类会节省内存吗?

java - 使用 JSF 和 Spring Architecture 的好例子

java - JVM 进程与 JVM 堆内存使用情况

java - 当您滚动超过某个点时, Swing 滚动 Pane 会发出通知

java - 包装到另一个类中的不可变整数(按值调用)

java - <c :foreach jsp iterate over list

r - 协方差矩阵和相关矩阵之间的转换

具有可变列表的 Julia 不可变结构