2017-08-28 38 views
1

我無法在Java中創建一個類不可變。我知道我的構造函數和我的getter方法都有問題。從我讀過的內容來看,這聽起來像是我需要製作不引用原始對象的新對象。使Java類不可變

我想要一些幫助,如果可能的話,讓我知道如何讓這個類不可變。

public class FMatrix implements Matrix { 

    private final int rows, columns; 
    private final int[][] matrix; 
    //TODO: implement interface. 

    public FMatrix(int[][] matrix) { 
    int[][] matrix1; 
    if (matrix.length == 0) { 
     rows = 0; 
     columns = 0; 
    } else { 
     rows = matrix.length; 
     columns = matrix[0].length; 
    } 
    this.matrix = new int[rows][columns]; 
    //this.matrix = matrix; 
    } 

    /** 
    * Returns the element at particular point in the matrix. 
    * @param y y position 
    * @param x x position 
    * @return element 
    */ 
    @Override 
    public int getElement(int y, int x) { 
    return matrix[y][x]; 
    } 

    /** 
    * Returns the number of rows in the matrix. 
    * @return rows 
    */ 
    @Override 
    public int getRows() { 
    return rows; 
    } 

    /** 
    * Returns the number of columns in the matrix. 
    * @return columns 
    */ 
    @Override 
    public int getColumns() { 
    return columns; 
    } 

    /** 
    * Returns this matrix scaled by a factor. That is, computes kA where k is a 
    * constant and A is a matrix (this object). 
    * 
    * @param scalar scalar 
    * @return matrix 
    */ 
    @Override 
    public Matrix scale(int scalar) { 

    int value; 
    int[][] mat1; 
    int newRows = getRows(); 
    int newColumns = getColumns(); 

    mat1 = new int[newRows][newColumns]; 
    //this.matrix = new int[newRows][newColumns]; 
    FMatrix newMatrix = new FMatrix(mat1); 
    for (int i = 0; i < getRows(); i++) { 
     for (int j = 0; j < getColumns(); j++) { 
     value = getElement(i, j) * scalar; 
     mat1[i][j] = value; 
     } 
    } 

    return newMatrix; 
    } 

    /** 
    * Returns this matrix added with another matrix. That is, computes A+B where 
    * A and B are matrices (this object, and another respectively). 
    * @param other addend 
    * @return matrix 
    * @throws RuntimeException if matrices do not have matching dimensions. 
    */ 
    @Override 
    public Matrix plus(Matrix other) { 
    int value; 
    int newRows = getRows(); 
    int newColumns = getColumns(); 

    if (newRows != other.getRows() || newColumns != other.getColumns()) { 
     throw new RuntimeException(); 
    } 
    FMatrix newMatrix = new FMatrix(matrix); 
    for (int i = 0; i < newRows; i++) { 
     for (int j = 0; j < newColumns; j++) { 
     value = getElement(i, j) + other.getElement(i, j); 
     this.matrix[i][j] = value; 
     } 
    } 
    return newMatrix; 
    } 

    /** 
    * Returns this matrix subtracted by another matrix. That is, computes A-B 
    * where A and B are matrices (this object, and another respectively). 
    * @param other subtrahend 
    * @return matrix 
    * @throws RuntimeException if matrices do not have matching dimensions. 
    */ 
    @Override 
    public Matrix minus(Matrix other) { 
    int value; 
    int newRows = getRows(); 
    int newColumns = getColumns(); 

    //throw exception if dimensions do not match 
    if (newRows != other.getRows() || newColumns != other.getColumns()) { 
     throw new RuntimeException("Dimensions do not match"); 
    } 
    FMatrix newMatrix = new FMatrix(matrix); 
    for (int i = 0; i < newRows; i++) { 
     for (int j = 0; j < newColumns; j++) { 
     value = getElement(i, j) - other.getElement(i, j); 
     this.matrix[i][j] = value; 
     } 
    } 
    return newMatrix; 

    } 

    /** 
    * Returns true if this matrix matches another matrix. 
    * @param other another matrix 
    * @return equality 
    */ 
    @Override 
    public boolean equals(Object other) { 
    if (other == this) { 
     return true; 
    } else { 
     return false; 
    } 

    } 

    /** 
    * Returns a string representation of this matrix. A new line character will 
    * separate each row, while a space will separate each column. 
    * @return string representation 
    */ 
    @Override 
    public String toString() { 
    String str = ""; 
    for (int i = 0; i < rows; i++) { 
     for (int j = 0; j < columns; j++) { 
     str += getElement(i, j) + " "; 
     if (j == columns - 1) { 
      str += "\n";   //add a new line for next row 
     } 
     } 
    } 
    return str; 
    } 

主要方法

公共靜態無效的主要(字串[] args){

int[][] data1 = new int[0][0]; 
int[][] data2 = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; 
int[][] data3 = {{1, 4, 7}, {2, 5, 8}, {3, 6, 9}}; 

Matrix m1 = new FMatrix(data1); 
Matrix m2 = new FMatrix(data2); 
Matrix m3 = new FMatrix(data3); 

System.out.println("m1 --> Rows: " + m1.getRows() + " Columns: " + m1.getColumns()); 
System.out.println("m2 --> Rows: " + m2.getRows() + " Columns: " + m2.getColumns()); 
System.out.println("m3 --> Rows: " + m3.getRows() + " Columns: " + m3.getColumns()); 

//check for reference issues 
System.out.println("m2 -->\n" + m2); 
data2[1][1] = 101; 
System.out.println("m2 -->\n" + m2); 

//test equals 
System.out.println("m2==null: " + m2.equals(null));    //false 
System.out.println("m3==\"MATRIX\": " + m2.equals("MATRIX")); //false 
System.out.println("m2==m1: " + m2.equals(m1));     //false 
System.out.println("m2==m2: " + m2.equals(m2));     //true 
System.out.println("m2==m3: " + m2.equals(m3));     //false 

//test operations (valid) 
System.out.println("2 * m2:\n" + m2.scale(2)); 
System.out.println("m2 + m3:\n" + m2.plus(m3)); 
System.out.println("m2 - m3:\n" + m2.minus(m3)); 

//test operations (invalid) 
//System.out.println("m1 + m2" + m1.plus(m2)); 
//System.out.println("m1 - m2" + m1.minus(m2)); 

}

下面是在主測試的輸出。問題是在調用.scale()方法後,m2對象不應該被更改。

m1 --> Rows: 0 Columns: 0 
m2 --> Rows: 3 Columns: 3 
m3 --> Rows: 3 Columns: 3 
m2 --> 
1 2 3 
4 5 6 
7 8 9 

m2 --> 
1 2 3 
4 101 6 
7 8 9 

m2==null: false 
m3=="MATRIX": false 
m2==m1: false 
m2==m2: true 
m2==m3: false 
2 * m2: 
2 4 6 
8 202 12 
14 16 18 

m2 + m3: 
2 6 10 
6 106 14 
10 14 18 

m2 - m3: 
1 2 3 
4 101 6 
7 8 9 
+1

你爲什麼試圖使它不可變?你明白什麼是不可變的手段嗎? – shmosel

+2

這是(AFAIK)幾乎不可變的;你只需要在返回矩陣[y] [x]中克隆矩陣數組;' – 2017-08-28 19:47:40

+0

我不明白 - 類似乎對我來說是不可改變的 - 除了構造函數,什麼都不改變類數據。 – corsiKa

回答

0

您的操作方法似乎有一個錯誤。考慮scale

FMatrix newMatrix = new FMatrix(mat1); 
for (int i = 0; i < getRows(); i++) { 
    for (int j = 0; j < getColumns(); j++) { 
    value = getElement(i, j) * scalar; 
    mat1[i][j] = value; 
    } 
} 

return newMatrix; 

這是偉大的,因爲你的分配[i][j]mat1。但看看你在plus做什麼!

FMatrix newMatrix = new FMatrix(matrix); 
for (int i = 0; i < newRows; i++) { 
    for (int j = 0; j < newColumns; j++) { 
    value = getElement(i, j) + other.getElement(i, j); 
    this.matrix[i][j] = value; 
    } 
} 
return newMatrix; 

哦,親愛的,你改變this.matrix[i][j] - 類不再是一成不變的。但更重要的是,你返回的價值也是被破壞的。所以我相信你只需要修復這個bug,你的類實際上是不可變的。

其他錯誤:

  • 你永遠不會從構造函數賦值。您需要將參數中的值複製到內部數組中。所以你不能做到這一點

    int[][] matrix = new int[3][3]; 
    FMatrix f = new FMatrix(matrix); 
    matrix[1][1] = 42; // broken immutability 
    

    現在,它是不是一個問題,因爲你永遠不分配從參數值到你的矩陣...所以

副本是沒有必要後顧之憂。

public FMatrix(int[][] matrix) { 
    if (matrix.length == 0) { 
    rows = 0; 
    columns = 0; 
    } else { 
    rows = matrix.length; 
    columns = matrix[0].length; 
    } 
    this.matrix = new int[rows][0]; 
    for(int row = 0; row < rows; row++) { 
     this.matrix[rows] = matrix[rows].clone(); 
    } 
} 
+0

Ahhhhh我明白你的意思了。我對這些修補程序進行了加減法,結果越來越好!現在我唯一面臨的問題是來自「data2 [1] [1] = 101;」的行。因爲m2現在在該位置引用該值。感謝您的幫助! –

+0

邁克爾,正如我在「其他錯誤」中所提到的那樣,您必須從構造函數中複製值。我會舉一個例子。 – corsiKa

+0

@MichaelF在最後添加的示例。 – corsiKa