My Face class does not seem to be immutable even though I already declared it as final, how do I correct it?

南笙酒味 提交于 2019-12-11 15:58:13

问题


I am trying to make my Face class immutable such that my Face object will not change once it has been initialized. This is what I have so far:

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;
  }
}

However, when I try to run the following:

int[][] g = f.getGrid();
g[1][1] = 9;

I expect f to remain as

010203
040507
070809

but I end up getting

010203
040906
070809

instead. Is my Face object not made immutable even though I have already declared the class as final?


回答1:


You need to make a defensive copy of the input grid in the constructor.

Also, the fields should be private as well, and the class should be final too, although I suspect those last two points are not the cause of your problem.

Not tested:

  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;
  }



回答2:


Your problem could be that your constructor doesn't clone the incoming array. So maybe the code that creates the Face class instance later manipulates the array it passed to the new Face object!

Unfortunately, there is no way to create truly immutable arrays in the Java. Declaring an array as final only prevents you from changing the array as a whole, it is still possible to change individual rows, columns, slots in that array.

If you want immutable collections, you need to turn actual Collection classes and then use the methods within the Collections class to create unmodifiable views over them.




回答3:


Be careful when using clone.

On arrays, it does a shallow copy. The following snippet explains it better:

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;


来源:https://stackoverflow.com/questions/55175471/my-face-class-does-not-seem-to-be-immutable-even-though-i-already-declared-it-as

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!