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

时间:2013-10-24 21:32:12

标签: java oop final

Efficient Java 中,Joshua Bloch写道:

  

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

// Potential security hole!
public static final Thing[] VALUES = { ... };
  

请注意许多IDE生成返回的访问器   对私有数组字段的引用,导致了这个问题。   有两种方法可以解决问题。你可以制作公共阵列   private并添加一个公共不可变列表:

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

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

private static final Thing[] PRIVATE_VALUES = { ... };
public static final Thing[] values() {
    return PRIVATE_VALUES.clone();
}

我的问题是:

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


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

2 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:5)

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