为什么将私有字段的副本声明为`final`

alf*_*sin 4 java oop final

高效的Java中, Joshua Bloch写道:

请注意,非零长度数组始终是可变的,因此类具有公共静态最终数组字段或返回此类字段的访问器是错误的.如果类具有此类字段或访问者,则客户端将能够修改该数组的内容.这是安全漏洞的常见原因:

// Potential security hole!
public static final Thing[] VALUES = { ... };
Run Code Online (Sandbox Code Playgroud)

请注意,许多IDE生成的访问器返回对私有数组字段的引用,从而导致了这个问题.有两种方法可以解决问题.您可以将公共数组设为私有并添加公共不可变列表:

private static final Thing[] PRIVATE_VALUES = { ... };
public static final List<Thing> VALUES =
Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
Run Code Online (Sandbox Code Playgroud)

或者,您可以将数组设为私有,并添加一个返回私有数组副本的公共方法:

private static final Thing[] PRIVATE_VALUES = { ... };
public static final Thing[] values() {
    return PRIVATE_VALUES.clone();
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  • 为什么要回复一个final变量 - 如果它只是一个副本?


毕竟,在用户想要修改它(用于她/他自己的用途)的情况下,我们实际上强迫她/他创建另一个非最终副本,这没有意义.

Boa*_*ann 6

Arrays.asList包装原始数组.它不会复制数据.Collections.unmodifiableList还包装原始列表而不是复制数据.

这就是你返回一个unmodifiableList包装器的原因,因为否则,对返回的列表所做的更改Arrays.asList将写入原始的私有数组.

  • 因此换句话说,返回一个unmodifiableList可以避免复制列表的需要.(假设接收方法只需要从中读取.) (4认同)

Lou*_*man 5

这不是返回一个final对象 - 它只是将该方法声明为不可覆盖的.没有final对象 - 只有最终变量(引用或原始),最终方法和最终类.