当前位置: 首页 > 知识库问答 >
问题:

为什么要将一个私有字段的副本声明为“final”`

戈博易
2023-03-14

约书亚·布洛赫在高效的Java中写道:

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

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

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

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

我的问题是:

  • 为什么要费心返回一个最终变量-如果它只是一个副本?


毕竟,如果html" target="_blank">用户想要修改它(供她/他自己使用),我们实际上是在强迫她/他创建另一个非最终副本,这是没有意义的。

共有2个答案

王飞英
2023-03-14

这不是返回一个最终的对象,而是声明这个方法是不可重写的。没有最终的对象,只有一个最终变量(引用或基元),一个最终的方法和一个最终的类。

农明辉
2023-03-14

数组。asList包装原始数组。它不会复制数据<代码>集合。不可修改列表也会包装原始列表,而不是复制数据。

这就是为什么要返回一个不可修改的列表包装器,因为否则,对Arrays.as列表返回的列表所做的更改将写入原始私有数组。

 类似资料:
  • 根据我的理解 最后一个类只是一个不能扩展的类。 具有私有构造函数的类不能被实例化,除非该类中的表单。这使得从另一个类扩展它毫无用处。但这并不意味着它根本不能被子类化,在内部类中,我们可以扩展并调用私有构造函数。 所以我的理解是,如果我们创建了一个具有单个无参数私有构造函数的类,那么将该类声明为final并没有任何意义。那个么,为什么Java中的系统类声明为最终类,尽管它只有一个无参数的私有构造函数

  • 问题内容: 如果我用Java创建一个类,就会一直被告知惯例是将类的所有字段都设为私有。如果需要访问或更改它们,可以创建访问器和更改器方法。我确实了解私有变量的重要性,因为它们有助于降低复杂性并允许封装。 我不明白的是,如果我创建一个公共的accesor和mutator方法,那么变量不是公共的吗?在任何人都可以访问私有变量的情况下,为什么仍然习惯使用私有变量? 我还应该指出,我了解这些方法的重要性,

  • 我只是试图声明字段内的主方法在Java类与不同的访问说明符...但是我不能声明与访问说明符字段为公共,这是什么原因?

  • 我有一些奇怪的行为,我正努力向自己解释。浮点字段,称为“文本缩放”,变为零。 如果某些代码正在更改值,则可以解释这一点。然而,我希望通过将其设置为“私有最终浮点”,能够导致构建失败,或者至少是运行时异常,那么无论改变值的是什么,都将失败。但是如果我这样做,代码就不会失败——它工作得很好! 有谁能帮我理解这里可能发生的事情吗?为什么这个浮动会变成零,除非我把它设为最终值?这里有我不熟悉的Java i

  • 问题内容: 我读到要使一个类在Java中不可变,我们应该执行以下操作: Do not provide any setters Mark all fields as private Make the class final标记为私有 为什么需要步骤3?我为什么要上课呢? 问题答案: 如果你不标记该类,那么我可能会突然使你看似不变的类真正变得可变。例如,考虑以下代码: 现在,假设我执行以下操作: 注意

  • 根据我的理解,类被声明为final,以防止它被扩展/继承。因此,我认为在这方面可能会有安全性,也可能会有一些性能提升。 但这背后是否有一个非常具体的设计决策?比如说:实现某种设计模式?我确实在这里绕了一个类似的线!但答案并不是我想要的