在 Java 中将泛型子类型类信息传递给超类

2022-09-03 07:07:56

长期以来,我一直在Java中使用一个成语,用于在其(通常是抽象的)祖先类(es)的方法中使用(非抽象)类的类信息(不幸的是,我找不到此模式的名称):

public abstract class Abstract<T extends Abstract<T>> {
    private final Class<T> subClass;

    protected Abstract(Class<T> subClass) {
        this.subClass = subClass;
    }

    protected T getSomethingElseWithSameType() {
        ....
    }
}

其子类的示例:

public class NonGeneric extends Abstract<NonGeneric> {
    public NonGeneric() {
        super(NonGeneric.class);
    }
}

但是,我在定义子类时遇到了麻烦,该子类具有自己的泛型参数:Abstract

public class Generic<T> extends Abstract<Generic<T>> {
    public Generic() {
        super(Generic.class);
    }
}

此示例不可编译。同样,不能使用例如 甚至使用通配符,如 .Generic<T>.classGeneric<?>

我还尝试将超类中泛型类型的声明替换为 ,但这也不是可编译的。T? extends T

有没有办法让这个模式与泛型基类一起工作?


答案 1

传递 (通常为构造函数) 的实例的“模式”(习语)是使用类文本作为运行时类型标记,并用于保留对泛型类型的运行时引用,否则将擦除该引用。Class<T>

解决方案是首先将绑定到以下内容的令牌类更改为:

Class<? extends T>

然后对你的泛型子类提出类似的要求,就像你对超类所做的那样;让具体类传递类型标记,但您可以将其作为参数正确键入:

这些类在没有强制转换或警告的情况下进行编译:

public abstract class Abstract<T extends Abstract<T>> {
    private final Class<? extends T> subClass;

    protected Abstract(Class<? extends T> subClass) {
        this.subClass = subClass;
    }
}

public class NonGeneric extends Abstract<NonGeneric> {
    public NonGeneric() {
        super(NonGeneric.class);
    }
}

public class Generic<T> extends Abstract<Generic<T>> {
    public Generic(Class<? extends Generic<T>> clazz) {
        super(clazz);
    }
}

最后,在具体类中,如果将用法声明为其自己的类,则不需要在任何地方进行强制转换:

public class IntegerGeneric extends Generic<Integer> {
    public IntegerGeneric() {
        super(IntegerGeneric.class);
    }
}

我还没有弄清楚如何在没有强制转换的情况下创建(匿名或不匿名)的实例:Generic

// can someone fill in the parameters without a cast?
new Generic<Integer>(???);     // typed direct instance
new Generic<Integer>(???) { }; // anonymous

我认为这是不可能的,但我欢迎被展示出来。


答案 2

您在这里遇到的主要问题是,具体参数化类型没有类文本。这是有道理的,因为参数化类型没有任何运行时类型信息。因此,在本例中,您只能使用原始类型的类文本。Generic.class

参考:

好吧,这很好,但是给你一个与 不兼容的.解决方法是找到一种方法将其转换为 ,但您也无法直接执行此操作。您必须向 添加一个中间强制转换,它表示 的所有实例化的族。然后向下转换为 ,这将删除编译器错误,尽管您将出现未经检查的强制转换警告。您可以对构造函数进行批注以删除警告。Generic.classClass<Generic>Class<Generic<T>>Class<Generic<T>>Class<?>ClassClass<Generic<T>>@SuppressWarnings("unchecked")

class Generic<T> extends Abstract<Generic<T>> {     
    public Generic() {
        super((Class<Generic<T>>)(Class<?>)Generic.class);
    }
}

推荐