如何限制该子类不能通用?

Vis*_*ant 18 java compiler-construction generics inheritance throwable

编译时错误:泛型类可能不是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);
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的编译时错误是出于以下§jls-8.1.2中给出的原因,并在此问题中进行了解释:

如果泛型类是Throwable(第11.1.1节)的直接或间接子类,则是编译时错误.

由于Java虚拟机的catch机制仅适用于非泛型类,因此需要此限制.

题:

  • 如何限制子类java.lang.Throwable不是泛型类?

  • 或者更通用的问题是,如何限制任何类的子类不能通用?

Jk1*_*Jk1 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");
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,禁用类型是一种带编码的类型,因此如果没有编译器代码自定义,您不能对自定义类使用相同的技术.

完整的源代码


chr*_*her 10

如何限制java.lang.Throwable的子类不是泛型类?

这是决定将特殊情况编写到编译器本身.原因在于这个问题详述.基本上,这与可再生类型有关.你可以在这里阅读这个术语.简而言之,如果类型在编译时完全可用,则类型是可重新生成的.例如,通用类型是不可恢复的,因为它们的类型通过类型擦除来删除.出现在catch块中的对象需要可恢复的.

或者更通用的问题,如何限制类的子类不能通用?

那么有几个选择..

目前,在Java的正常范围内没有选项可以做到这一点.它没有某种final实现阻止将泛型应用于子类.正如评论中所解释的,您可以得到的最接近的是扩展编译器并专门为您的类添加规则.这个解决方案让我的脊椎发抖.躲闪吧.这意味着您的代码只会使用的Java版本,并且任何想要使用您的代码的人都必须安装相同的版本.

显然,另一种选择是扩展Throwable,但这确实不是一个好主意.它为您的类添加了大量功能,并为您的类的接口添加了许多新方法,您永远不会使用它们.从OOP的角度来看,为了拥有此功能,您牺牲了班级的完整性.