我知道当在 Class 之前使用 final 关键字时,该 Class 不能被另一个 Class 继承。
但除了不可变类之外,我从未见过它在 Java 编码中的真正用途。
在哪些情况下,真正需要在 Class 之前使用 final 关键字?
并且它不会降低 Java 语言的可重用性吗?
我知道当在 Class 之前使用 final 关键字时,该 Class 不能被另一个 Class 继承。
但除了不可变类之外,我从未见过它在 Java 编码中的真正用途。
在哪些情况下,真正需要在 Class 之前使用 final 关键字?
并且它不会降低 Java 语言的可重用性吗?
一个final
类不能被子类化。这样做是出于安全和效率的原因。Java API 中的一些类是final
,例如java.lang.System。有时安全性和不变性比可重用性更重要。
普遍的看法是,将类或方法声明为 final 会使编译器更容易内联方法调用,但这种看法是不正确的(或者至少,被大大夸大了)。
final 类和方法在编程时可能会给您带来很大的不便——它们限制了您重用现有代码和扩展现有类的功能的选择。虽然有时一个类被定为 final 是有充分理由的,例如强制不变性,但使用 final 的好处应该超过不便之处。性能增强几乎总是损害良好的面向对象设计原则的一个不好的理由,当性能增强很小或不存在时,这确实是一个糟糕的权衡。
另请阅读此开放封闭原则:
软件实体(类、模块、函数等)应该对扩展开放,但对修改关闭。
final 类不能被继承。因此,如果您希望没有人可以继承您的类,那么您可以将其声明为 final。所以你已经回答了你自己的问题。所以主要用途是
两者都是出于安全原因使用。通过使用您的关键类来保护您的系统被更改。作为一个理由还不够吗?
final关键字可以与类一起使用以提供安全性。我们可以以String为例。String 类是不可变的,也是 final的,以增强 java 中文件处理的安全性。
虽然,性能也是一个原因(假设您已经知道为确保多次使用同一个 String 对象而不必多次创建/重新声明它而维护的内部字符串池),但主要原因为什么 String 在 Java 中变得不可变是“安全性”。惊讶吗?让我们明白为什么。
假设您需要打开一个要求用户进行身份验证的安全文件。假设有两个用户名为“user1”和“user2”,他们分别有自己的密码文件“password1”和“password2”。显然'user2' 不应该访问'password1' 文件。
正如我们所知,Java 中的文件名是使用字符串指定的。即使您创建了一个“文件”对象,您也只能将文件名作为字符串传递,并且该字符串作为其成员之一在文件对象中维护。
如果 String 是可变的,'user1' 可以使用他的凭据登录,然后在 JVM 实际放置本机 OS 系统之前设法将他的密码文件名(字符串对象)的名称从 'password1' 更改为 'password2'调用打开文件。这将允许“user1”打开 user2 的密码文件。可以理解的是,这会导致 Java 中的一个重大安全漏洞。我知道这里有很多“可能”,但您肯定会同意,它会打开一扇门,允许开发人员有意或无意地破坏许多资源的安全性。
由于字符串是不可变的,JVM 可以确保相应文件对象的文件名实例成员将继续指向相同的未更改的“文件名”字符串对象。作为 File 类中的“final”的 'filename' 实例成员无论如何都不能被修改为指向任何其他 String 对象,该对象指定任何其他文件,而不是预期的文件(即,用于创建 File 对象的文件)。
我对此进行了研究,并在 Hardcore Java 上阅读了此内容,出版商:O'Reilly ISBN:0-596-00568-7
为什么类被标记为最终:
有两种方法可以使班级决赛。第一种是在类声明中使用关键字final:
public final class SomeClass {
// . . . Class contents
}
使类成为 final 的第二种方法是将其所有构造函数声明为私有:
public class SomeClass {
public final static SOME_INSTANCE = new SomeClass(5);
private SomeClass(final int value) {
}
如果发现它实际上是一个final,那么将它标记为final可以为您省去麻烦,以演示查看这个Test类。第一眼看上去很公开。
public class Test{
private Test(Class beanClass, Class stopClass, int flags)
throws Exception{
// . . . snip . . .
}
}
不幸的是,由于该类的唯一构造函数是私有的,因此无法扩展该类。在 Test 类的情况下,没有理由认为该类应该是最终的。Test 类是隐式 final 类如何导致问题的一个很好的例子。
因此,当您通过将构造函数设为私有来隐式地使类最终成为最终时,您应该将其标记为最终。
一个final
类不能被子类化。即使它有一些缺点,这对于提高安全性也是必要的。
例如类java.lang.String
是final
. 因此,您不能子类化String
,并且可以确定String
参数永远不会是有害的子类(例如发送String
某处)。