Java 14 中 Record 文档中“浅层不可变”的含义

2022-09-01 14:17:07

我正在阅读记录的文档,但不理解“浅层不可变”一词。我们所说的浅层不可变是什么意思?如果它是不可变的,为什么我们需要一个复制构造函数?为什么是两个“Hello Worlds!”?

对于所有记录类,以下不变量必须成立:如果记录 R 的分量是 c1、c2、...cn,则如果复制记录实例,如下所示:

 R copy = new R(r.c1(), r.c2(), ..., r.cn());  // copy constructor ?

那么一定是这种情况。r.equals(copy)


答案 1

浅不可变意味着,如果一个类有字段,这些字段将被视为 .但是,它们的字段(即字段的字段)不需要是 。finalfinal

您不需要实现构造函数,它已经以这种方式为您实现。但是,如果您选择自己实现它,例如用于参数验证,那么这种不变量应该成立。


答案 2

如果将某个类视为其他类和基元(整数、数组等)的复合或层次结构,则浅层不可变性仅指第一级的不可变性(常量)。

它与术语“深度不变性”相反,后者指的是整个层次结构的不变性。您听到的有关不可变性的大多数有形好处(例如隐式线程安全)仅适用于非常不可变的东西。

考虑此类

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

推荐