问题
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