将通用子类类信息传递给Java中的超类

err*_*ist 15 java generics inheritance abstract-class

我长期以来在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() {
        ....
    }
}
Run Code Online (Sandbox Code Playgroud)

其子类的示例:

public class NonGeneric extends Abstract<NonGeneric> {
    public NonGeneric() {
        super(NonGeneric.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我在定义其子类Abstract有自己的泛型参数时遇到了问题:

public class Generic<T> extends Abstract<Generic<T>> {
    public Generic() {
        super(Generic.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

这个例子不可编译; 同样,不可能使用例如Generic<T>.class甚至使用通配符来指定泛型类型Generic<?>.

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

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

Boh*_*ian 11

传递Class<T>(通常是构造函数)实例的"模式"(惯用法)是使用类文字作为运行时类型标记,并用于保持对泛型类型的运行时引用,否则将被擦除.

解决方案首先是将绑定的令牌类更改为:

Class<? extends T>
Run Code Online (Sandbox Code Playgroud)

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

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

public class IntegerGeneric extends Generic<Integer> {
    public IntegerGeneric() {
        super(IntegerGeneric.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

我没有想出如何在没有强制转换的情况下创建Generic(匿名或非匿名)实例:

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

我不认为这是可能的,但我欢迎以其他方式表现出来.