Java 类中的最终数组实例变量并重置引用



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

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

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));
    }
}
这与

最终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;

只需将一张纸上写的内容复制到一张新纸上即可。这只是"房子"(在本例中为数组对象(的地址。

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

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

final int[] data

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

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

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

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

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

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

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

最新更新