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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19312641/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 16:00:17  来源:igfitidea点击:

Passing generic subtype class information to superclass in Java

javagenericsinheritanceabstract-class

提问by errantlinguist

I've long used an idiom in Java for using the class information of a (non-abstract) class in the methods of its (generally abstract) ancestor class(es) (unfortunately I can't find the name of this pattern):

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

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

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

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

An example of a subclass thereof:

其子类的示例:

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

However, I'm having trouble defining a subclass of Abstractwhich has its own generic parameters:

但是,我无法定义Abstract具有自己通用参数的子类:

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

This example is not compilable; likewise, it is not possible to specify the generic types using e.g. Generic<T>.classor even to use a wildcard like Generic<?>.

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

I also tried replacing the declaration of generic type Tin the superclass to ? extends T, but that isn't compilable either.

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

Is there any way I can get this pattern to work with generic base classes?

有什么办法可以让这个模式与通用基类一起工作吗?

采纳答案by Bohemian

The "pattern" (idiom) of passing an instance of Class<T>(typically to the constructor) is using Class Literals as Runtime-Type Tokens, and is used to keep a runtime reference to the generic type, which is otherwise erased.

传递 的实例Class<T>(通常传递给构造函数)的“模式”(习惯用法)是使用类文字作为运行时类型令牌,并用于保持对泛型类型的运行时引用,否则将被删除。

The solution is firstly to change the token class bound to:

解决方法是首先将token类绑定到:

Class<? extends T>

and then to put a similar requirement on your generic subclass as you did with your super class; have the concrete class pass a type token, but you can type it properly as a parameter:

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

These classes compile without casts or warnings:

这些类编译时没有强制转换或警告:

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);
    }
}

And finally at the concrete class, if you declare the usage as its own class, it doesn't require a cast anywhere:

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

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


I haven't figured out how to create an instance of Generic(anonymous or not) without a cast:

我还没有弄清楚如何在Generic没有演员的情况下创建(匿名与否)的实例:

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

I don't think it's possible, but I welcome being shown otherwise.

我不认为这是可能的,但我欢迎被其他人展示。

回答by Rohit Jain

The major problem you have got here is, there is no class literal for concrete parameterized type. And that makes sense, since parameterized types don't have any runtime type information. So, you can only have class literal with raw types, in this case Generic.class.

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

Reference:

参考:

Well, that's fine, but Generic.classgives you a Class<Generic>which is not compatible with Class<Generic<T>>. A workaround is to find a way to convert it to Class<Generic<T>>, but that too you can't do directly. You would have to add an intermediate cast to Class<?>, which represents the family of all the instantiation of Class. And then downcast to Class<Generic<T>>, which will remove the compiler error, though you will an unchecked cast warning. You can annotate the constructor with @SuppressWarnings("unchecked")to remove the warning.

好吧,那很好,但Generic.class会给你一个Class<Generic>Class<Generic<T>>. 解决方法是找到一种将其转换为 的方法Class<Generic<T>>,但这也不能直接执行。您必须添加一个中间转换 to Class<?>,它代表 的所有实例化的系列Class。然后向下转换为Class<Generic<T>>,这将消除编译器错误,尽管您将收到未经检查的转换警告。您可以注释构造函数@SuppressWarnings("unchecked")以删除警告。

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

回答by Mikhail

There is no need in Class<T> subClassargument. Change:

没有必要Class<T> subClass争论。改变:

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

to:

到:

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

and everything will compile.

一切都会编译。