Search code examples
javaimmutabilitytranspose

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


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?


Solution

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