【问题标题】:private constructor and final私有构造函数和final
【发布时间】:2017-01-06 15:58:14
【问题描述】:

为什么将只有私有构造函数的类标记为 final 是一种好习惯?我的猜测是,是为了让其他程序员知道它不能被子类化。

【问题讨论】:

  • 方法 -> 构造函数?你不是说上课吗?
  • 你的意思是把一个类标记为final?
  • 严格来说,只要可以从子类的构造函数访问构造函数,就可以对具有私有构造函数的类进行子类化,例如子类是嵌套类的情况。

标签: java


【解决方案1】:

通常认为(例如,Josh Bloch 和 C# 的设计者)将所有内容标记为 final 是一种很好的做法,除非您有明确的理由不这样做。假设您的意思是类,那么只有私有构造函数的类不能被子类化是正确的。因此,最终可能被认为是多余的,但正如您所说,它具有文档价值。正如 Marc 所建议的,它也可能有助于优化。

【讨论】:

  • “经常考虑”的是谁? [需要引用]
  • 将所有内容标记为最终结果?我认为您的意思是变量和参数。但是将所有类和方法都标记为 final 并不是一个好主意。这将极大地限制您的应用程序的可扩展性。
  • @Hardcoded,他写道“将所有内容标记为 final 除非你有明确的理由不这样做”。 IE。您只允许扩展设计为可扩展的类
  • @Donal、Josh Bloch(“设计和记录继承,否则禁止它”)和 C# 的设计者都认为不可扩展性应该是默认设置。看到这个previous question
  • 我的意思是,最好支持您的回答中似乎有争议的部分,并提及您所关注的权威(或 SO 问题)。 (就个人而言,我在哲学上总体上不同意他们的观点——我倾向于采用开放世界模型,尽管强烈使用委托——但这不是我打算在这里提出的论点。)
【解决方案2】:

将类设为 final 会带来一些(小的)性能提升,因为 JIT 编译器可以内联该类的功能。我不知道这是否属于“良好做法”,但我看到了它的优势。

【讨论】:

  • JIT 编译器是否无论如何都看不到该类是否加载了任何具体的子类以及方法是否被覆盖?我想在这种情况下它无论如何都可以内联,无论类/方法是否被声明为final。再说一次,我不是 JIT 专家,只是好奇:-)
  • HotSpot 判断类是否加载了子类。课程是否标记为final 没有区别。
  • 这有很有趣的含义。例如,如果你动态加载一个之前没有加载子类的类的子类,HotSpot 编译器需要重新编译该类!
  • @Stephen C:这就是我的想法。也许这种行为在以后的 JVM 版本中有所改变。
  • @Stephen C:其实是编译后的调用代码需要回退。
【解决方案3】:

您的意思是“具有私有构造函数的 ”是吗?

final 类不能被子类化。这可能代表一个设计决策。并非所有的类都被设计为子类,所以如果你的不是,最好明确标记它,以避免以后出现细微的错误。

只有私有构造函数的类不能被外部世界实例化(既不是子类)。这可能对例如有用单例,或您想要控制创建哪些类的实例的类。例如。在 Java5 之前,typesafe enum 模式使用了这个。

【讨论】:

  • 是的,我刚才看到了。对不起。我删除了反对票。
【解决方案4】:

我们通过将构造函数设为私有来将类标记为最终类,以避免子类化。

这是一种很好的做法,如果我们不希望人们重写我们的类方法并更改功能或将函数添加到我们的类中。

例如,String 和 Math 类是 final 类,我们不能对其进行扩展或子类化,这是为了确保没有人会改变它们的行为。

【讨论】:

    【解决方案5】:

    带有私有构造函数的最终类:

    • 类不能有子类,我们不能扩展最终类。
    • 具有私有构造函数的类,我们无法创建该类的对象。

    这意味着该类的其他方法将是静态的,以便该类可以访问它们。

    【讨论】:

    • 我认为第二点不成立。我们仍然可以通过静态工厂方法创建构造函数都是私有的类的对象。
    猜你喜欢
    • 1970-01-01
    • 2013-09-02
    • 2020-10-19
    • 1970-01-01
    • 1970-01-01
    • 2017-06-13
    • 2011-02-08
    • 2011-04-20
    • 2011-10-30
    相关资源
    最近更新 更多