我长期以来在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>.class
甚至可以使用Generic<?>
之类的通配符。
我也尝试将超类中泛型类型T
的声明替换为? extends T
,但这也不可编译。
有没有办法让这个模式与泛型基类一起使用?
答案 0 :(得分:11)
传递Class<T>
实例(通常是构造函数)的“模式”(惯用语)是使用Class Literals as Runtime-Type Tokens,用于保持对泛型类型的运行时引用,否则擦除。
解决方案首先是将绑定的令牌类更改为:
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
我认为这不可行,但我欢迎以其他方式展示。
答案 1 :(得分:3)
您遇到的主要问题是,具体参数化类型没有类文字。这是有道理的,因为参数化类型没有任何运行时类型信息。因此,您只能使用原始类型的类文字,在本例中为Generic.class
。
参考:
嗯,没关系,但是Generic.class
会为您提供与Class<Generic>
不兼容的Class<Generic<T>>
。解决方法是找到一种方法将其转换为Class<Generic<T>>
,但这也是你无法直接做到的。您必须向Class<?>
添加一个中间强制转换,它代表Class
所有实例化的系列。然后向下转换为Class<Generic<T>>
,这将删除编译器错误,但您将获得未经检查的强制转换警告。您可以使用@SuppressWarnings("unchecked")
注释构造函数以删除警告。
class Generic<T> extends Abstract<Generic<T>> {
public Generic() {
super((Class<Generic<T>>)(Class<?>)Generic.class);
}
}
答案 2 :(得分:-1)
Class<T> subClass
论证中没有必要。变化:
protected Abstract(Class<T> subClass) {
this.subClass = subClass;
}
为:
protected Abstract(Class subClass) {
this.subClass = subClass;
}
一切都会编译。