我们可以不使用final关键字来避免继承吗?

时间:2018-09-11 07:48:45

标签: java android final

我只想知道我可以有2个A类和B类。 我不想让B类扩展A类。 我应该在A类中应用什么技术,以便B类不能继承A类。 不想打入A级决赛。还有其他解决方案,而不是将A类定为最终解决方案?

7 个答案:

答案 0 :(得分:2)

实际上,我尝试遵循的做法,以及乔什·布洛赫(Josh Bloch)在他的《有效的Java》一书中所建议的,恰恰是您所学的相反的规则:除非您考虑过继承,否则请设计类要被继承,并记录必须如何继承类,则应始终禁用继承。

我建议您阅读本章“有效的Java”(您不会后悔的),并向告诉您此规则的人展示。

禁止继承的最明显原因是不可变性。不可变的对象易于使用(只有一个状态),可以被缓存,可以在许多对象之间共享,并且本质上是线程安全的。如果该类是可继承的,则任何人都可以扩展该类,并通过添加可变属性来使其可变。 https://stackoverflow.com/a/10464466/5010396

答案 1 :(得分:1)

这不可能以“很好的方式”进行。 Java语言允许您在类定义中使用final关键字,也可以不使用。

正如其他人所指出的:您可以将所有构造函数设为私有,然后子类化实际上变得不可能,因为子类构造函数没有父类构造函数可以调用。

如果需要实例化A,您仍然可以使用工厂方法,例如:

public class A {
  private A() { ... }
  private A(String foo) { ... }

  public static A newInstance(String foo) { return new A(foo); }

例如。

但是请记住:代码是为人类读者编写的。如果您的意图要参加最后一堂课,那么正确答案是使用该关键字final

加上:将您的类定为final可以使JIT做更多的事情,因为它不必随时担心多态性(因此它可以直接内联方法代码,而无需任何其他检查)。因此,使用final可以稍微改善性能。另一方面,它限制了您对事物进行单元测试的能力(例如:标准Mockito无法模拟最终课程)。

答案 2 :(得分:1)

您可以将A类的构造函数标记为私有。 :)

PS:如果您还想避免反射攻击,请向构造函数抛出一些错误  并将其标记为私有。

答案 3 :(得分:0)

我不了解您的需求的特定用例,但这可能行得通。

如果您愿意在B进行更改

在B的每个构造函数中检查它是否是A的一个实例,然后引发错误。

if(A.class.isAssignableFrom(B.class)) {
        System.out.println(true);
        throw new IllegalStateException();
    }
    else
        System.out.println(false);

答案 4 :(得分:0)

实际上,您可以将类A放在没有修饰符的包中(package modifier)。

package com.example.package1;

// Class A with package modifier.
class A {

}

并将类B放在另一个包中

package com.example.package2;

// Class B cannot extends from class A, compiler error.
public class B extends A {

}

限制是,只有同一包中的类才能从类A扩展。

答案 5 :(得分:0)

您可以选择这样限制构造函数。

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

有关更多详细信息,请查看帖子。

https://stackoverflow.com/a/451229/6742601

答案 6 :(得分:0)

您可以执行以下一项操作来避免继承而不使用final关键字:

  • 使用私有构造函数。
  • 标记每个方法final,以使子代无法覆盖它们。
  • 如果要限制某些不需要的子代的继承,则在构造函数中抛出运行时异常(尽管v.rude),例如
    if (this.getClass() != FavoriteChild.class) throw new RuntimeException("Not Allowed")