【问题标题】:Stopping inheritance without using final在不使用 final 的情况下停止继承
【发布时间】:2009-01-16 17:00:43
【问题描述】:

除了将类声明为 final 或将其构造函数声明为私有之外,还有其他停止类继承的方法吗?

【问题讨论】:

  • final 有什么问题?
  • 您能解释一下为什么您要避免使用 final 关键字吗?
  • 可能是因为涉及到创建子类的框架。
  • @dtsazza 框架可以做一些你通常不会让用户代码做的事情;框架可以在运行时更改私有构造函数的保护级别。 AFIK 你不能乱用 final...
  • 为什么每个人都在回答:当问题本身说“除了最终...”时,“使用最终”我认为他们是对的,但重点是,这不是问题所在。我想我们已经习惯了我们没有抓住重点的“主观和争论”问题。

标签: java inheritance


【解决方案1】:

评论

//Do not inherit please

【讨论】:

  • 我实际上相信这是有史以来最好的解决方案。你甚至可以描述为什么它不应该被继承。
【解决方案2】:

另外两个选项:

  • 使每个方法成为最终方法,这样人们就无法覆盖它们。这样可以避免从子类中意外调用方法。但这并没有停止子类化。

  • 将检查放入类的构造函数中:

    if (this.getClass() != MyClass.class) {
        throw new RuntimeException("Subclasses not allowed");
    }
    

    那么没有人可以实例化你的类的子类。

(不是我建议使用这些技术,我只是想到了。我会使用 final 类和/或私有构造函数)

【讨论】:

  • 老鼠们,我只是想自己发布一个例外。
  • 除非finalize方法被覆盖,否则可以恢复实例。
  • +1 我不认为这个问题会有一个真正的答案,但我想这与你将得到的一样接近。
  • @Chris Lively:必须始终调用来自超类的构造函数。你可以“覆盖”构造函数(虽然没有覆盖构造函数,因为构造函数不是继承的),但是你不能从超类中“跳过”构造函数。
【解决方案3】:
  • 使用final
  • 使用私有构造函数
  • 使用评论:

    // do not inherit
    
  • 使用 javadoc 注释

  • 使每个方法都成为最终方法,这样人们就无法覆盖它们
  • 在类构造函数中使用运行时检查:

    if (this.getClass() != MyClass.class) {
        throw new RuntimeException("Subclasses not allowed");
    }
    

【讨论】:

【解决方案4】:

Final 就是为了解决这个问题而创建的。

【讨论】:

    【解决方案5】:

    使用final 是规范的方式。

    public final class FinalClass {
      // Class definition
    }
    

    如果您想防止个别方法被覆盖,您可以将它们声明为 final。 (我只是在这里猜测,为什么你会想要避免让整个班级都进入决赛。)

    【讨论】:

    • 我猜的原因类似于 java.lang.String。
    【解决方案6】:

    将您的构造函数设为私有并提供工厂函数来创建实例。

    当您想从多个实现中选择一个合适的实现,但又不想像中那样允许任意子类化时,这会特别有用

    abstract class Matrix {
       public static Matrix fromDoubleArray(double[][] elemens) {
         if (isSparse(elements)) {
          return new SparseMatrix(elements);
        } else {
          return new DenseMatrix(elements);
        }
      }
      private Matrix() { ... }  // Even though it's private, inner sub-classes can still use it
      private static class SparseMatrix extends Matrix { ... }
    }
    

    【讨论】:

      【解决方案7】:

      我不得不说这通常是糟糕的形式。尽管几乎总是存在某些有效的情况,但我不得不说在 OO 世界中停止继承通常不是一个好主意。阅读Open-Closed Principlehere。保护您的功能,但不要让进来并支持它的人成为不可能...

      【讨论】:

      • 继承被高估了。除非你为子类设计你的类,否则你最好避免它。
      • +1 对彼得的评论。正如我在其他地方所说的(很多次!)我希望类默认是密封的(C#)/最终的(Java)。继承很棒,当你真正需要它时 - 但如果你只是使用它而不仔细考虑它可能会很痛苦。
      • "为继承设计和记录,否则禁止。" -- Josh Bloch,有效的 Java 第 17 条
      • 阅读 Michael Feather 的书“有效地使用遗留代码”。它使我完成了许多棕地项目,而诸如您无法触及的类和方法之类的事情是主要的痛点。即使您不打算使用它,功能 XYZ 也将需要它。所有关于未来的证明......
      • @Jon Skeet:我想根据我的经验,我只是没见过。拿.NET BCL(打开/保存/打印)中的任何对话框来说,不能对它们做任何危险的事情,因为它们是密封的,很痛苦。但是这个讨论可能应该是在另一个带有“主观”标签的问题中
      【解决方案8】:

      不使用最终类,基本上可以将所有构造函数设为私有:

      public class A {
          private A() {} //Overriding default constructor of Java
      }
      

      虽然通过禁止创建此类的对象也会使此类抽象化,但是由于任何继承都需要构造函数中的super();,并且由于构造函数是私有的,因此编译错误将是最大的错误当一个人试图继承那个类时得到。 但是,我建议使用 final 代替,因为它的代码更少,并且包含创建对象的选项。

      【讨论】:

        猜你喜欢
        • 2012-05-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-06
        相关资源
        最近更新 更多