我们可以不使用 final 关键字来避免继承吗?
Can we avoid inheritance without using final keyword?
我只想知道我可以有 2 个 classes A 和 B。
我不想让 class B 扩展 class A。
我应该在 class A 中应用什么技术,这样 class B 就不能继承 class A。
不想 class 决赛。除了 class 决赛还有其他解决方案吗?
这在 "nice ways" 中是不可能的。 java 语言允许您在 class 定义中使用 final
关键字,或者不使用它。
正如其他人指出的那样:您可以将所有构造函数设为私有,然后 subclassing 变得几乎不可能,因为 subclass 构造函数没有要调用的 super class 构造函数.
如果您需要实例化 A,您仍然可以使用工厂方法,例如:
public class A {
private A() { ... }
private A(String foo) { ... }
public static A newInstance(String foo) { return new A(foo); }
例如
但请记住:代码是为人类读者编写的。如果您的 意图 是最终 class,那么 正确的 答案是使用关键字 final
。
另外:使你的 class final 允许 JIT 做更多的事情,因为它在任何时候都不必担心多态性(因此它可以直接内联方法代码,而无需任何额外的检查)。所以使用 final
可以稍微提高性能。另一方面,它限制了你对事物进行单元测试的能力(例如:标准 Mockito 不能模拟最终 classes)。
我不明白你的要求的具体用例,但这可以工作。
如果您愿意在 B
中进行更改
在 B 的每个构造函数中检查它是否是 A 的实例然后抛出错误。
if(A.class.isAssignableFrom(B.class)) {
System.out.println(true);
throw new IllegalStateException();
}
else
System.out.println(false);
您可以将 A class 的构造函数标记为私有。 :)
PS:如果你也想避免反射攻击,那么从构造函数中抛出一些错误
并将其标记为私有。
您可以选择像这样在构造函数中进行限制。
if (this.getClass() != MyClass.class) {
throw new RuntimeException("Subclasses not allowed");
}
有关详细信息,请查看 post。
事实上,我尝试遵循的做法以及 Josh Bloch 在他的 Effective Java 一书中推荐的做法与您被告知的规则正好相反:除非您认为关于继承,将您的 class 设计为继承,并记录了您的 class 必须如何继承,您应该始终禁用继承。
我建议阅读 Effective Java 的这一章(你不会后悔买了它),并把它展示给告诉你这条规则的人。
禁止继承的最明显原因是不变性。不可变对象使用简单(只有一种状态),可以缓存,可以在多个对象之间共享,并且本质上是线程安全的。如果 class 是可继承的,任何人都可以扩展 class 并通过添加可变属性使其可变。
您可以执行以下操作之一来避免不使用 final
关键字的继承:
- 使用私有构造函数。
- 标记每个方法
final
这样 children 就不能覆盖它们。
- 如果想限制某些不需要的继承 children(尽管 v.rude),例如
,则在构造函数中抛出运行时异常
if (this.getClass() != FavoriteChild.class) throw new RuntimeException("Not Allowed")
我只想知道我可以有 2 个 classes A 和 B。 我不想让 class B 扩展 class A。 我应该在 class A 中应用什么技术,这样 class B 就不能继承 class A。 不想 class 决赛。除了 class 决赛还有其他解决方案吗?
这在 "nice ways" 中是不可能的。 java 语言允许您在 class 定义中使用 final
关键字,或者不使用它。
正如其他人指出的那样:您可以将所有构造函数设为私有,然后 subclassing 变得几乎不可能,因为 subclass 构造函数没有要调用的 super class 构造函数.
如果您需要实例化 A,您仍然可以使用工厂方法,例如:
public class A {
private A() { ... }
private A(String foo) { ... }
public static A newInstance(String foo) { return new A(foo); }
例如
但请记住:代码是为人类读者编写的。如果您的 意图 是最终 class,那么 正确的 答案是使用关键字 final
。
另外:使你的 class final 允许 JIT 做更多的事情,因为它在任何时候都不必担心多态性(因此它可以直接内联方法代码,而无需任何额外的检查)。所以使用 final
可以稍微提高性能。另一方面,它限制了你对事物进行单元测试的能力(例如:标准 Mockito 不能模拟最终 classes)。
我不明白你的要求的具体用例,但这可以工作。
如果您愿意在 B
在 B 的每个构造函数中检查它是否是 A 的实例然后抛出错误。
if(A.class.isAssignableFrom(B.class)) {
System.out.println(true);
throw new IllegalStateException();
}
else
System.out.println(false);
您可以将 A class 的构造函数标记为私有。 :)
PS:如果你也想避免反射攻击,那么从构造函数中抛出一些错误 并将其标记为私有。
您可以选择像这样在构造函数中进行限制。
if (this.getClass() != MyClass.class) {
throw new RuntimeException("Subclasses not allowed");
}
有关详细信息,请查看 post。
事实上,我尝试遵循的做法以及 Josh Bloch 在他的 Effective Java 一书中推荐的做法与您被告知的规则正好相反:除非您认为关于继承,将您的 class 设计为继承,并记录了您的 class 必须如何继承,您应该始终禁用继承。
我建议阅读 Effective Java 的这一章(你不会后悔买了它),并把它展示给告诉你这条规则的人。
禁止继承的最明显原因是不变性。不可变对象使用简单(只有一种状态),可以缓存,可以在多个对象之间共享,并且本质上是线程安全的。如果 class 是可继承的,任何人都可以扩展 class 并通过添加可变属性使其可变。
您可以执行以下操作之一来避免不使用 final
关键字的继承:
- 使用私有构造函数。
- 标记每个方法
final
这样 children 就不能覆盖它们。 - 如果想限制某些不需要的继承 children(尽管 v.rude),例如
,则在构造函数中抛出运行时异常if (this.getClass() != FavoriteChild.class) throw new RuntimeException("Not Allowed")