Java 我的Face类似乎不是一成不变的,即使我已经声明它为final,我如何更正它?

Java 我的Face类似乎不是一成不变的,即使我已经声明它为final,我如何更正它?,java,immutability,transpose,Java,Immutability,Transpose,我试图使我的Face类不可变,这样我的Face对象在初始化后就不会改变。这就是我到目前为止所做的: public class Face{ protected final int[][] grid; protected Face half; public Face(int[][] grid){ this.grid = grid; } public Face rotateRight(){ int rows = 3; int cols = 3;

我试图使我的Face类不可变,这样我的Face对象在初始化后就不会改变。这就是我到目前为止所做的:

public class Face{
  protected final int[][] grid;
  protected Face half;

  public Face(int[][] grid){
    this.grid = grid;
  }


  public Face rotateRight(){
    int rows = 3;
    int cols = 3;
    int[][] transposedArray = new int[3][3];

    for (int i = 0; i<rows; i++){
      for (int j = 0; j<cols; j++){
        transposedArray[i][j]=grid[rows-j-1][i];
      }
    }

    return new Face(transposedArray);
  }

  public Face rotateLeft(){
    int rows = 3;
    int cols = 3;
    int[][] transposedArray = new int[3][3];

    for (int i = 0; i < 3; i++){
      for (int j = 0; j < 3; j++){
        transposedArray[2-j][i] = grid[i][j];
      }
    }
    return new Face(transposedArray);
  }

  public Face rotateHalf(){
    half = this.rotateRight();
    half = half.rotateRight();
    return half;
  }

  public int[][] getGrid(){
    return (this.grid).clone();
    }

  public String toString(){
    String str = "";
    for (int i = 0; i<3;i++){
      for (int j = 0; j<3; j++){
        str += String.format("%02d",grid[i][j]);
      }
    }
    String str1 = str.substring(0,6);
    String str2 = str.substring(6,12);
    String str3 = str.substring(12,18);
    return str1+"\n"+str2+"\n"+str3;
  }
}
我希望f保持不变

010203
040507
070809
但我最终得到了

010203
040906
070809

相反。即使我已经将类声明为final,我的Face对象也不是不可变的吗?

您需要在构造函数中创建一个输入网格的防御性副本

此外,字段也应该是
private
,类也应该是
final
,尽管我怀疑最后两点不是问题的原因

未测试:

  public Face(int[][] grid){
    int temp[][] = new int[ grid.length ][];
    for( int i = 0; i < temp.length; i++ ) 
      temp[i] = Arrays.copyOf( grid[i], grid[i].length );
    this.grid = temp;
  }
公共面(int[][]网格){
int temp[][]=新int[grid.length][];
对于(int i=0;i
您的问题可能是构造函数没有克隆传入数组。因此,可能创建Face类实例的代码稍后会处理它传递给新Face对象的数组

不幸的是,没有办法在Java中创建真正不可变的数组。将数组声明为final只会阻止您更改整个数组,仍然可以更改该数组中的单个行、列和插槽


如果想要不可变的集合,则需要打开实际的集合类,然后使用集合类中的方法在其上创建不可修改的视图。

使用克隆时要小心

在阵列上,它执行浅拷贝。下面的代码片段对此进行了更好的解释:

int[] c0 = new int[]{1, 2, 3};
int[] c1 = new int[]{4, 5, 6};
int[] c2 = new int[]{7, 8, 9};
int[][] grid = new int[][]{c0, c1, c2};
int[][] cloned = grid.clone();

assert cloned[0] == c0;
assert cloned[1] == c1;
assert cloned[2] == c2;

final
使变量(在本例中为引用)不可变。你不能改变引用,但你可以改变引用所指的东西。详细说明pvg所说的:
final
的重要一点是你不能改变引用所指的东西,不是你不能,或者你的对象不再是不变的
final
并不能阻止这一点,因此您必须自己制作对象的副本。
int[] c0 = new int[]{1, 2, 3};
int[] c1 = new int[]{4, 5, 6};
int[] c2 = new int[]{7, 8, 9};
int[][] grid = new int[][]{c0, c1, c2};
int[][] cloned = grid.clone();

assert cloned[0] == c0;
assert cloned[1] == c1;
assert cloned[2] == c2;