java - final详解 - static final class




在Java中使用final类 (14)

我正在阅读一本关于Java的书,它说你可以宣布整个班级都是final 。 我想不出任何我会使用它的地方。

我只是编程的新手,我想知道程序员是否真的在程序中使用它 。 如果他们这样做,他们什么时候使用它,这样我可以更好地理解它,并知道何时使用它。

如果Java是面向对象的,并且你声明了一个类final ,它不会阻止类具有对象特性的想法吗?


如果他们这样做,他们什么时候使用它,这样我可以更好地理解它,并知道何时使用它。

final堂课只是一个无法扩展的课程。

(这并不意味着所有对类的对象的引用都会像被声明为final 。)

如果在这个问题的答案中涵盖了最终声明的类是有用的:

如果Java是面向对象的,并且你声明了一个类final ,它不会阻止类具有对象特性的想法吗?

在某种意义上是的。

通过将类标记为final,可以禁用该代码部分的语言的强大而灵活的功能。 然而,有些类别不应该(并且在某些情况下不能)被设计成以良好的方式考虑子类别。 在这些情况下,将班级标记为最终班级是有意义的,即使它限制了面向对象。 (不过请记住,最后一堂课仍然可以延续另一个非最终课。)

相关文章: Java:何时创建最终的类



当添加新方法时, final class 可以避免打破公共API

假设在你的Base类的第一版上你做了:

public class Base {}

和客户做的:

class Derived extends Base {
    public int method() { return 1; }
}

然后,如果在版本2中想要将method方法添加到Base

class Base {
    public String method() { return null; }
}

它会破坏客户端代码。

如果我们使用了final class Base ,则客户端将无法继承,并且方法添加不会破坏API。


解决最终类问题:

有两种方法可以进行课堂决赛。 首先是在类声明中使用final关键字:

public final class SomeClass {
  //  . . . Class contents
}

做出类最后的第二种方法是将其所有构造函数声明为私有的:

public class SomeClass {
  public final static SOME_INSTANCE = new SomeClass(5);
  private SomeClass(final int value) {
  }

如果发现它是实际的最终版本,那么最后标记它可以节省您的麻烦,以便展示此Test类的外观。 乍一看是公开的。

public class Test{
  private Test(Class beanClass, Class stopClass, int flags)
    throws Exception{
    //  . . . snip . . . 
  }
}

不幸的是,由于该类的唯一构造函数是私有的,所以不可能扩展这个类。 在Test类的情况下,没有理由说该类应该是最终的。 Test类是隐式最终类如何导致问题的一个很好的例子。

所以你应该把它标记为final,当你隐式地通过使构造函数为私有进行类最终。


出于安全原因,当你想阻止类的继承时,final是重要的一种场景。 这使您可以确保您正在运行的代码不会被某人覆盖

另一个场景是优化:我似乎记得Java编译器内嵌了来自最终类的一些函数调用。 所以,如果你调用ax()而a被声明为final ,那么我们在编译时知道代码将会是什么,并且可以内联到调用函数中。 我不知道这是否实际完成,但最终它是一种可能性。


在Java中,具有final修饰符的项目不能更改!

这包括最终类,最终变量和最终方法:

  • 最终的课程不能由其他课程扩展
  • 最终变量不能被重新分配给另一个值
  • 最后的方法不能被覆盖

如果您将类层次结构想象为一棵树(就像它在Java中那样),抽象类只能是分支,而最终类只能是叶子。 属于这两个类别的类都可以是分支和叶子。

这里没有违反面向对象的原则,最后只是提供了一个很好的对称性。

在实践中,如果你希望你的对象是不可变的,或者如果你正在编写一个API,那么你希望使用final来向API的用户表明这个类只是不打算用于扩展。


如果该类标记为final ,则意味着该类的结构不能被任何外部修改。 最显而易见的是当你在做传统的多态继承时,基本上class B extends A是行不通的。 它基本上是一种保护代码的某些部分的方法(可扩展)

为了澄清,标记类final不会将其字段标记为final ,因此不会保护对象属性,而是保护实际的类结构。


当你做一个“最终”课时要小心。 因为如果你想为最终类编写一个单元测试,你不能为这个最终类继承子类,以便使用Michael C. Feathers的书“使用遗留代码有效工作”中描述的依赖断开技术“Subclass and Override Method” 。 在这本书中,Feathers说:“认真地说,很容易相信密封和最终是错误的错误,他们不应该被添加到编程语言中,但真正的错误在于我们,当我们直接依赖我们无法控制的图书馆,我们只是在寻求麻烦。“


把FINAL视为“终结” - 那个人不能生育后代了。 所以当你这样看的时候,你会遇到很多现实世界的场景,需要你给这个班级标记一个'行尾'标记。 它是域驱动设计 - 如果您的域名要求给定的ENTITY(类)不能创建子类,则将其标记为FINAL。

我应该注意到,没有什么能阻止你继承“应该被标记为final”的类。 但是,这通常被归类为“继承的滥用”,因为大多数情况下您希望从类中的基类继承一些函数。

最好的方法是查看域并让它决定你的设计决定。


最后一堂课是一个无法扩展的课程。 也可以将方法声明为final来指示不能被子类覆盖。

如果您编写API或库并且希望避免被扩展来改变基本行为,那么防止类被子类化可能特别有用。


最好的例子是

public final class String

这是一个不可变的类,不能被扩展。 当然,除了让课堂最终成为不变的东西还不止这些。


相关阅读:鲍勃马丁的开放 - 封闭原则

重要报价:

软件实体(类,模块,函数等)应该为扩展打开,但为修改而关闭。

final关键字是在Java中强制执行此操作的手段,无论是在方法上还是在类上使用。


面向对象不是关于继承,而是关于封装。 继承破坏封装。

宣布课堂决赛在很多情况下都是非常有意义的。 代表“颜色”或“金钱”等“价值”的任何对象都可能是最终的。 他们自立。

如果你正在编写库,除非你明确地将它们缩进来派生,否则使你的类成为最终的。 否则,人们可能派生你的类并重写方法,打破你的假设/不变量。 这也可能有安全隐患。

“有效的Java”中的Joshua Bloch建议明确地设计继承或禁止它,他指出为继承设计并不那么容易。







final