为什么这个 class 被认为是可变的?

Why is this class considered mutable?

public class A {
    private int[] values;

    public int[] getValues() {
        return values;
    }
}

我正在读的一本书说它不是不可变的,因为 values 是引用类型。除了在 class.

中创建一个 main 方法之外,我看不出有什么方法可以改变 values

它是可变的,因为你可以通过你公开的方法改变values的内容

A obj = new A(...) // values gets filled here
int[] leak = obj.getValues()
leak[0] = 42

这意味着您的 values 属性 现在包含已被外部修改的信息。为了让它不可变,你应该 return 数组的一个副本,这样你就可以确定没有外部代理可以修改它,你应该让它成为最终的,这样就不会创建可以暴露状态和使其再次可变:

public final class A {
  private int[] values;

  public int[] getValues() {
    return Arrays.copyOf(values);
  }
}

您可以获得引用并更改元素数组:

 A.getValues()[0] = -100500

您可以使用反射来更改值字段,或在其他地方(可能是作者的意思)或使用继承,如下所示。

例如,

不可变class:

import java.util.Arrays;

public final class A {
    private int[] values;

    public int[] getValues() {
        return values;
    }
}

不可变对象:

import java.util.Arrays;

public class A {
    private final int[] values;

    public A(int[] values) {
        this.values = null == values ? null : Arrays.copyOf(values);
    }

    public int[] getValues() {
        return Arrays.copyOf(values);
    }
}

不可变class和对象:

import java.util.Arrays;

public final class A {
    private final int[] values;

    public A(int[] values) {
        this.values = null == values ? null : Arrays.copyOf(values);
    }

    public int[] getValues() {
        return Arrays.copyOf(values);
    }
}

它实际上不是通过 values 数组可变的,如其他答案中所述:该数组是 null,因为它从未被初始化,并且您不能通过getter.

的结果

它是可变的,因为您可以对其进行子类化,并添加可变状态:

class AA extends A {
  String foo;
}

AA aa = new AA();
aa.foo = "foo";
A a = aa;
aa.foo = "bar";  // Mutates the state of a.

请注意,在 Oracle Java 教程中有一个 "Strategy for defining immutable objects",在 Effective Java 第二版中有一个不可变对象的必需属性列表 项目 15:"Minimize mutability".

values,数组是引用类型。您可以找到有关参考文献 here 的更多信息。这意味着当 getValues() returns values 时,它实际上返回一个指向它的指针(每次都会取消引用,因为 Java 没有显式指针)。由于 values 是私有的,因此无法重新分配引用本身,但可以更改内容。

所以像 a.getValues()[0]++ 这样的东西会增加 values 的第一个元素,假设它不为空。