1

我尝试了以下代码,它有一个final名为 的实例变量data。这是在构造函数中使用int[]参数实例化的。如果 int[] 数组的元素发生更改,则更改将反映在实例变量中并显示在show()'s输出中。但是,如果我将外部数组设置为 null 或新数组,则更改不会反映在 show() 输出中。

为什么会这样?如果外部数组由 ext[0]=x 更改,则更改显示在 inst.variable 中。如果将 ext 引用设置为新对象,则不会发生。

public class MutabilityTest {
    public static void main(String[] args) {
    int[] ext =  new int[] {1,2,3,4,5};
        FMutable xmut = new FMutable(ext);
        mut.show();    //shows [1,2,3,4,5]
        System.out.println("changed ext array");
        ext[0] = 99;
        System.out.println("ext:"+Arrays.toString(ext)); //[99,2,3,4,5]
        mut.show();    //shows [99,2,3,4,5]
        System.out.println("set ext array to new");
        ext = new int[]{8,8,8,8} 
        System.out.println("ext:"+Arrays.toString(ext)); //[8,8,8,8]
        mut.show();//expected [8,8,8,8] but got [99,2,3,4,5]
        ext = null;
        System.out.println("ext:"+Arrays.toString(ext)); //null
        mut.show(); //shows same [99,2,3,4,5]
    }
}
class FMutable{
    private final int[] data;
    public FMutable(int[] indata){
    this.data = indata;
    }
    public void show(){
    System.out.println("XMutable:"+Arrays.toString(this.data));
    }
}
4

4 回答 4

3

data这与最终或其他领域无关。您可以更简单地看到完全相同的效果:

int[] x = { 1, 2, 3, 4, 5 };
int[] y = x;

y[0] = 10;
System.out.println(Arrays.toString(x)); // 10, 2, 3, 4, 5
y = new int[] { 3, 3, 3, };
System.out.println(Arrays.toString(x)); // 10, 2, 3, 4, 5

区分变量、它们的值和对象很重要。把变量想象成一张纸。它可以有一个写在上面的原始值,或者一个家庭地址。

该行:

int[] y = x;

或在您的示例代码中:

this.data = indata;

只需将写在一张纸上的内容复制到一张新纸上。这只是“房子”的地址(在这种情况下是数组对象)。

现在这两张纸本身是独立的——改变其中一张纸上写的内容不会改变另一张纸上写的内容。但是,如果您按照一张纸上的地址去房子,请进行更改(例如粉刷前门),然后按照另一张纸上的地址去房子(当他们还在的时候)同样)然后是的,你会看到新粉刷的门。这就是您对阵列本身进行更改时所看到的。

于 2013-10-01T07:01:55.097 回答
1

ext只是另一个指向与data实例数组相同的内存位置的引用。如果您设置ext为 null 它只会设置对数组的ext引用null而不是data数组。

于 2013-10-01T06:59:14.390 回答
1
final int[] data

这意味着您的数组对象是最终的(您可以初始化一次,之后不能更改)但index's不是。

您已通过构造函数初始化。

public FMutable(int[] indata){
    this.data = indata;
}

ext是指向同一个对象的另一个引用。对同一对象的任何更改也会对final data字段产生影响,因为它们都引用了相同的Object

但由于参考数据是最终的,您无法重新初始化。并将ext = new int[]{8,8,8,8}创建一个新数组,而 ext 将指向该数组。

于 2013-10-01T06:59:19.757 回答
1

ext = new int[]{8,8,8,8}为变量创建一个新数组,ext但不影响data对象中的字段。data请注意,如果不是最终的,也会发生相同的效果!

final仅表示您可以设置一次引用,但是仍然可以操作该对象。

于 2013-10-01T07:00:11.493 回答