为什么这个 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
的第一个元素,假设它不为空。
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
的第一个元素,假设它不为空。