编译时错误:泛型类可能不是java.lang.Throwable的子类
public class TestGenericClass<E> extends Exception {
/*Above line will give compile error, the generic class TestGenericClass<E> may
not subclass java.lang.Throwable*/
public TestGenericClass(String msg) {
super(msg);
}
}
以上编译时错误是出于 § jls-8.1.2中给出的原因,如下所述,并在this question中进行了解释:
如果泛型类是Throwable(第11.1.1节)的直接或间接子类,则是编译时错误。
由于Java虚拟机的catch机制仅适用于非泛型类,因此需要此限制。
问题:
如何限制java.lang.Throwable
的子类不是通用类?
或者更通用的问题是,如何限制任何类的子类不能通用?
答案 0 :(得分:20)
如何限制java.lang.Throwable的子类不会 泛类?
这是OpenJDK编译器执行检查的方式:
import com.sun.tools.javac.code.Symbol.*;
private void attribClassBody(Env<AttrContext> env, ClassSymbol c) {
....
// Check that a generic class doesn't extend Throwable
if (!c.type.allparams().isEmpty() && types.isSubtype(c.type, syms.throwableType))
log.error(tree.extending.pos(), "generic.throwable");
正如您所看到的,禁止类型是一种带编码的类型,因此如果没有编译器代码自定义,您就不能对自定义类使用相同的技术。
答案 1 :(得分:10)
如何限制java.lang.Throwable的子类不是泛型类?
这是决定将特殊情况编写到编译器本身。原因详见this question。基本上,这与 reifiable 类型有关。您可以阅读此术语here。简而言之,如果类型在编译时完全可用,则类型是可重新生成的。例如,通用类型是不可恢复的,因为它们的类型通过类型擦除来删除。出现在catch
块中的对象需要可再生。
或者更通用的问题,如何限制类的子类不能通用?
那里有几个选项..
目前,在Java的正常范围内没有选项可以做到这一点。它没有某种final
实现阻止将通用性应用于子类。正如评论中所解释的,您可以得到的最接近的是扩展编译器并为您的类添加专门的规则。这个解决方案让我的脊椎发抖。躲闪吧。这意味着您的代码只能使用您的版本的Java,并且任何想要使用您的代码的人都必须安装相同的版本。
显然,另一种选择是扩展Throwable
,但这并不是一个好主意。它为您的类添加了大量功能,并为您的类的接口添加了许多新方法,您永远不会使用它们。从OOP的角度来看,您为了拥有此功能而牺牲了班级的完整性。
答案 2 :(得分:1)
如果您愿意将错误延迟到运行时,可以在超类构造函数中使用use reflection来查看子类是否声明了任何类型参数。
public class Example {
public static class ProhibitsGenericSubclasses {
public ProhibitsGenericSubclasses() {
if (getClass().getTypeParameters().length > 0)
throw new AssertionError("ProhibitsGenericSubclasses prohibits generic subclasses (see docs)");
}
}
public static class NonGenericSubclass extends ProhibitsGenericSubclasses {}
public static class GenericSubclass<T> extends ProhibitsGenericSubclasses {}
public static void main(String[] args) {
System.out.println(new NonGenericSubclass());
System.out.println(new GenericSubclass<Object>());
}
}
此代码打印
Example$NonGenericSubclass@15db9742
Exception in thread "main" java.lang.AssertionError: ProhibitsGenericSubclasses prohibits generic subclasses (see docs)
at Example$ProhibitsGenericSubclasses.<init>(Example.java:12)
at Example$GenericSubclass.<init>(Example.java:17)
at Example.main(Example.java:21)
如果要禁止层次结构中所有类的类型参数,而不仅仅是最派生的类,则需要使用Class#getSuperclass()
向上移动层次结构。