我正在阅读Records的文档, 但不理解“浅不可变”一词。浅不可变是什么意思?如果它是不可变的,为什么我们需要一个复制构造函数?为什么是两个“Hello Worlds!”?
对于所有记录类,以下不变量必须保持:如果记录 R 的组件是 c1、c2、...cn,那么如果记录实例被复制如下:
R copy = new R(r.c1(), r.c2(), ..., r.cn()); // copy constructor ?
那么它一定是这样的r.equals(copy)
。
我正在阅读Records的文档, 但不理解“浅不可变”一词。浅不可变是什么意思?如果它是不可变的,为什么我们需要一个复制构造函数?为什么是两个“Hello Worlds!”?
对于所有记录类,以下不变量必须保持:如果记录 R 的组件是 c1、c2、...cn,那么如果记录实例被复制如下:
R copy = new R(r.c1(), r.c2(), ..., r.cn()); // copy constructor ?
那么它一定是这样的r.equals(copy)
。
浅不可变意味着,如果一个类有字段,则这些字段被视为final
. 但是,它们的字段(即字段的字段)不需要是final
.
您不需要实现构造函数,它已经为您实现了这种方式。但是如果您选择自己实现它,例如用于参数验证,那么这个不变量应该成立。
如果您将一个类视为其他类和基元(整数、数组等)的组合或层次结构,那么浅不变性是指仅第一级的不变性(恒定性)。
它与术语“深度不变性”形成对比,后者指的是整个层次结构的不变性。您听到的关于不可变性的大多数有形好处,例如隐式线程安全,仅适用于深度不可变的东西。
考虑这个类
class Foo {
private final MutableBar bar;
//ctor, getter
}
这个类是浅不可变的。它不能直接改变,但可以间接改变,例如
foo.getBar().setSomeProperty(5);
所以它不是深度不变的。
另一个浅不变性的例子,只使用原语
class Foo {
private final int[] ints;
Foo(int[] ints) {
this.ints = ints;
}
}
这可以像这样变异
int[] ints = {1};
Foo foo = new Foo(ints);
ints[0] = 2;
对于较小的层次结构,有时将浅不可变的类设为深度不可变很简单。它通常涉及防御性副本,或将可变类转换为不可变的变体。
class Foo {
private final int[] ints;
Foo(int[] ints) {
// copy to protect against the kind of mutation shown above
this.ints = Arrays.copyOf(ints, ints.length);
}
// if you must have a getter for an array, make sure not to return the array itself,
// otherwise the caller can change it.
// for performance reasons, consider an immutable List instead - no copy required
int[] getInts() {
return Arrays.copyOf(ints, ints.length);
}
}