在不可变类中,为什么字段被标记为私有?

在创建不可变类时使字段为私有有什么好处?

我已经看到为什么在创建不可变类时,字段被声明为私有? 但我从这篇文章中得不到任何理解。

有人可以解释一下吗?

最好的解释方法是举个例子:

  public class Immutable { private final char[] state = "Hi Mom".getChars(); public char[] getState() { return state.clone(); } } 

这里我们有一个正确封装的,不可变的类。 没有什么可以改变状态(模数讨厌的反思技巧)。

现在让我们改变对该字段的访问权限:

  public class Immutable { public final char[] state = "Hi Mom".getChars(); public char[] getState() { return state.clone(); } } 

请注意,我们仍然在getState中制作防御性副本……如前所述……但现在有人可以这样做:

  Immutable mu = new Immutable(); mu.state[1] = 'o'; 

……我们所谓的不可变对象的状态已发生变化。

这就是为什么保持字段private是一个好主意的一个原因。 (显然,这仅适用于引用类型。)

第二个原因是封装。 将字段声明为私有隐藏实现细节,这可以降低不必要的交叉耦合的风险。 如果我不这样做,那么我(或其他程序员)可能会想要编写依赖于Immutable内部的代码。 如果我需要改变它,那将导致问题; 例如,将state类型更改为String 。 像“要检查/更改更多代码”中的问题。

第三个原因是非私人(尤其是public )领域可能成为子类化的障碍。 如果我将一个字段声明为public字段,那么我不能在子类中声明它。 如果我想隐藏字段或修改子类中字段的行为(通过覆盖)……我不能。 相反,如果字段是私有的,并且通过实例方法进行访问,我可以在子类中覆盖这些方法。 或者我可以选择不使用该字段。

没有任何理由将不可变对象的最终字段设为私有。 这只是一种误解。

一些答案表明,如果一个字段不是私有的,并且它指向一个可变对象,那么有人可能会去修改那个可变对象,这当然是正确的,但后来我们进入了一个真正的哲学问题。不可变对象。 如果一个对象包含可变对象,它仍然可以被称为不可变对象吗? 对象的可变性是否依赖于它引用的对象的可变性?

我想说,不可变对象的最后一个字段需要被私有的唯一场景是,如果该字段是对不可变的对象的引用。 在所有其他情况下,将最终字段保持公开是完全可以的。

public final引用类型字段引用的对象仍可通过该字段进行修改。 (您不能做的是更改字段以引用其他对象。)

要禁止不需要的修改,您需要将该字段设为private

公共字段可以从任何类访问任何类并进行修改。 但是使字段成为私有和最终并使用构造函数注入/防御副本 ,您确保该类是完全不可变的

非私有字段仍然可以被读取访问 – 如果该字段是对象,则可以调用该对象上的可变操作。

将字段设为私有可以防止这种可能性。

 final class A{ final List l = new ArrayList(); } 

假设您有列表,并且您将此列表作为final列表,它的引用根本没有修改。

但是这个列表很容易被外部类访问,并且很容易修改它的内容。

所以要防止我们必须添加private访问说明符。

如果您将使用public字段,其他对象将能够更改“几乎不可变”对象的状态,这将破坏封装并使其成为可变对象。