何时应该使用"final"?

12

在日常编程(包括web开发)中,是否有特定的原因需要声明一个类或方法为final?请提供一个真实世界的例子来说明应该如何使用。

顺便说一下,我之所以问这个问题,是因为我正在尝试挑选一个“鲜为人知”的关键字并掌握它


1
我能想到的一个特定用途是被弃用的遗留类。在这种情况下,“final”被用于停止该代码的进一步传播。 - Michał Tatarynowicz
啊,好的...你最初的问题没有提到使用“final”关键字来修饰方法,而这比修饰整个类要更加常用。 - Nik Reiman
6个回答

13

它可以防止其他程序员对您的类进行不想要的操作。因此,您可以设计它,使他们不会被诱惑去覆盖它并以那种方式滥用它,而不是只写一个注释说“不要使用这个类来做XXX”。

编辑: 因为需要一个例子,我描述一个可能会发现这个关键字实用的情况…比如说你有一个定义了两个对象如何相互通信的类,比如一个监听器和通知器。显然,监听器类必须允许继承,但你可能想把通知器类设为final,以便它必须以“has-a”的关系使用。这样,你就可以从你的监听器对象中推断出它们接收到的消息的性质。

否则,从那个类继承将是可能的,会做各种疯狂的事情,例如扩展消息等。如果您不希望其他程序员这样做,则可以将该类设置为final。此外,这在广泛使用的公共API中可能更有意义,因为它还允许其他程序员轻松了解哪些类可用于子类化。

另外一个例子--假如你有一个基于缓冲区的流处理器,在read()/write()方法内部,你维护了关于对象当前状态的一些数据(即当前字节或其他)。无法保证任何子类化这个类的人在处理过程中调用超类的方法--由于这样的类可能只包含几个方法,最好将整个类设为final而不是每个方法。这再次强制使用该类的人“has-a”,而不是“is-a”,从而可以控制您期望代码将如何执行。

我同意你的观点,在一个蓝月球中使整个类final可能是很少需要做的事情,但很好PHP有这种能力,如果您选择行使它。


我认为无论如何,添加注释都是非常恰当的。 - Michał Tatarynowicz
你能提供一个现实世界的例子,说明你会以这种方式使用它吗? - Michał Tatarynowicz
2
是的,你也可以注释它,但最好假设与你的代码一起工作的人可能不会阅读文档或非常仔细地遵循它。通过设计来强制限制要更加有效。 - Nik Reiman

6

"强制组合优于继承"这句话说得非常简洁明了。您可以保证您的类具有某种行为,没有其他东西可以干扰,正如下一节所解释的那样,这也可以带来安全性方面的好处。


1
但是PHP类是不可变的,所以这并不适用。 - Michał Tatarynowicz

3

有些人声称,除非你特别打算允许并已经考虑了它的多态扩展影响,否则应该将所有类声明为final。我倾向于认为这意味着对与您的代码一起工作的其他人有很大的不信任,但不幸的是,有时确实如此。


最初我想问“每个类都应该声明为final或abstract吗?” - Michał Tatarynowicz
1
我肯定会拒绝那个。 :) - chaos
你能反驳一下吗? - Michał Tatarynowicz
当然。假设你的数据访问层(DAL)或ORM有一个行(Row)类,应用程序开发人员可以扩展该类以增加特定于表的功能,但不是必须的——仅使用Row本身就足够满足一般目的。将其声明为抽象类并强制子类化只是令人恼火和卖弄学识。 - chaos

2
在许多语言中,将一个类声明为final还提供了优化的好处,因为它不需要查看虚表以获取方法。
如果您想强制执行类的意图,并且意图是这样的,即不应该派生子类,则使用final;否则,没有显着的优势。
总的来说,这只是一种强制执行意图的机制。

0
最终类是一种无法被子类化的类,因此适用于任何您不希望创建派生类的情况。例如,在Java中,Math类是final的,因为Java不希望您能够重新定义绝对值的含义。

如果我创建了一个Math类的子类,我肯定希望能够重新定义绝对值的含义。由于子类意味着您想要修改类的工作方式,“final”防止子类化,而不是修改。为什么要阻止这样做呢? - Michał Tatarynowicz
@Pies - 嗯,根据给定的例子,绝对值只有一个含义,即使你想改变它也不应该。 - MattBelanger
你的意思是,“final”表示这个特定的类没有任何意义去扩展了? - Michał Tatarynowicz
实际上,Math类是最终的,因为它是一个静态实用程序类 - 它没有实例方法或属性。通常将这样的类设置为final以锁定它。 - Lawrence Dol
它还强制使用Math.xxx,而不是math = new Math ... math.xxx。 - Lawrence Dol

0

final(在C#中为sealed)可用于(类库设计者)强制执行类的某些基本行为。
例如,强制执行字符串具有不可变行为
Java中的字符串类被标记为final,在C#中被标记为sealed。
所有字符串都是不可变的,这种行为无法更改。


但是难道不可以将这个论点扩展到除了抽象类之外的所有类吗?换句话说,这是否意味着所有的类都应该是抽象的或者是最终版本? - Michał Tatarynowicz
@Pies:我不会为那个说法争论。不管怎样,这是一个有趣的问题。;)) - Kb.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接