1

我正在创建一个名为 Catalog 的非常简单的类。它将是一个不可变的类,并有一个 id 和 name 字段。

出于习惯,由于我不会为了可扩展性而明确记录这个东西,所以我将 final 修饰符放在类上。但是我想知道,由于这是一个如此简单的值类,如果将来有人决定他们可以使用它,那么将 final 修饰符关闭会不会很痛苦?

4

3 回答 3

2

您说“它将是不可变的”,因此将其设为 final 以确保该类不能被覆盖

于 2014-09-15T17:49:51.570 回答
1

在我看来,制作简单的值类型是一种很好的做法final。如果你想保证不变性,你实际上必须这样做。这也是(部分)为什么String,Integer等都是final.

如果你的类不是final,有人可以通过添加改变它的方法来扩展它。传递了扩展类型实例(向上转换为您的类型)的客户端会错误地认为处理不可变对象,而实际上它不是。

final在我自己的代码中,如果我没有在设计时明确考虑到可扩展性,我实际上会走得更远,制作几乎任何类。如果要支持扩展,请考虑提供抽象类或接口。这也符合方法的抽象、最终或空规则。

更新:为什么不变性需要一个类final?当然,还有其他方法可以确保对象的特定属性不被改变。

例如考虑一个RGBColor具有三个属性red和类型的green类。我们将所有三个都制作并在构造函数中设置它们一次。(我们可以另外制作它们并添加适当的 getter 方法,但这对于本次讨论并不重要。)当然,当且仅当比较对象是具有相同,和值的实例时,我们才会覆盖该方法以返回。bluebytefinalprivateequalstrueRGBColorredgreenblue

这看起来很无辜,但是如果有人决定RGBAColor通过添加alpha属性将我们的类扩展为一个类怎么办?自然,扩展器希望覆盖equals以也考虑该alpha值。假设我们的扩展器对不变性也不是很小心,因此使其成为alphanon-final并为其提供了一个 setter。

现在,如果给定一个 类型的对象RGBColor,我们不能安全地假设如果它与另一个比较相等,那么一分钟后它仍然会这样做。我们可以通过在我们的类中声明equalsas来防止这个(特殊问题)。但是,我们同样可以很好地制作整个类,因为在没有扩展相等概念的可能性的情况下扩展值类型几乎是无用的。(覆盖还有其他问题,例如它不是对称的。我通常对此不太满意。)finalRGBColorfinalequals

于 2014-09-15T17:50:29.957 回答
1

是的,不使用最后的修饰符可能会造成伤害。通过省略它,使用你的类的人不能相信它是不可变的,因此他们不能利用不可变对象的好处,例如线程安全。

于 2014-09-15T17:52:40.583 回答