如何限制该子类不能是泛型的?

编译时错误:泛型类不能子类 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中给出的原因,如下所示,并在此问题中进行了解释:

如果泛型类是 Throwable(§11.1.1) 的直接或间接子类,则为编译时错误。

此限制是必需的,因为 Java 虚拟机的捕获机制仅适用于非泛型类。

问题:

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

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


答案 1

如何限制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");

如您所见,禁止的类型是一种 harcode,因此如果不自定义编译器代码,则无法对自定义类使用相同的技术。

完整源代码


答案 2

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

这是将特殊情况写入编译器本身的决定。原因在这个问题中有详细说明。基本上,这与可再生的类型有关。您可以在此处阅读有关此术语的信息。简而言之,如果某个类型的类型在编译时完全可用,则该类型是可重用的。例如,泛型类型不可重用,因为它们的类型被类型擦除删除。出现在块中的对象必须是可重构的catch

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

嗯,有几个选择。

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

显然,另一种选择是 扩展 ,但这确实不是一个好主意。它向你的类添加了一大堆功能,并向类的接口添加了很多你永远不会使用的新方法。从 OOP 的角度来看,为了获得此功能,您正在牺牲类的完整性。Throwable


推荐