这是一个源自Build A Generic Tree With Inheritance的问题。我打开这个作为一个单独的问题,因为这不仅与树问题有关。这更像是一般和类问题。
为了通过代码更好地说明,我们有Tree
类,SubTree
类和WrongSubTree
类:
class Tree<TREE extends Tree<?,?>, DATA> {
}
class SubTree<STREE extends SubTree<?,?>, DATA> extends Tree<STREE, DATA> {
}
class WrongSubTree<WSTREE extends Tree<?,?>, DATA> extends Tree<WSTREE, DATA> {
}
在创建对象时,我们想检查泛型参数是否等于对象本身的类:
Tree<Tree<?,?>, String> tree01 = new Tree<Tree<?,?>, String>(); // equals : OK
Tree<SubTree<?,?>, String> tree02 = new Tree<SubTree<?,?>, String>(); // (!) not equals
SubTree<SubTree<?,?>, String> tree03 = new SubTree<SubTree<?,?>, String>(); // equals : OK
WrongSubTree<Tree<?,?>, String> tree04 = new WrongSubTree<Tree<?,?>, String>(); // (!) not equals
(请注意,上面的4行目前没有编译错误,也没有运行时异常。)
为此,我们尝试在构造函数中添加Class<>
参数:
class Tree<TREE extends Tree<?,?>, DATA> {
public Tree(Class<TREE> clazz) {
System.out.println(this.getClass());
System.out.println(clazz);
System.out.println();
if (this.getClass() != clazz)
throw new RuntimeException();
}
}
class SubTree<STREE extends SubTree<?,?>, DATA> extends Tree<STREE, DATA> {
public SubTree(Class<STREE> clazz) {
super(clazz);
}
}
class WrongSubTree<WSTREE extends Tree<?,?>, DATA> extends Tree<WSTREE, DATA> {
public WrongSubTree(Class<WSTREE> clazz) {
super(clazz);
}
}
(以上类定义是有效的java代码。)
但我不知道如何调用该构造函数:
Tree<Tree<?,?>, String> tree01a = new Tree<Tree<?,?>, String>(Tree.class);
// The constructor Tree<Tree<?,?>,String>(Class<Tree>) is undefined
Tree<Tree<?,?>, String> tree01b = new Tree<Tree<?,?>, String>(Tree<?,?>.class);
// Syntax error, insert "Dimensions" to complete ArrayType
上述两行都会导致编译错误。
我想这是因为构造函数public Tree(Class<TREE> clazz) {}
期待Class<Tree<?,?>>
,而不是Class<Tree>
。但是,我们无法Tree<?,?>.class
。
原因是我试图将课程改为:
class Tree<TREE extends Tree<?,?>, DATA> {
public Tree(Class<Tree> clazz) { // changed
System.out.println(this.getClass());
System.out.println(clazz);
System.out.println();
if (this.getClass() != clazz)
throw new RuntimeException();
}
}
Tree<Tree<?,?>, String> tree01a = new Tree<Tree<?,?>, String>(Tree.class);
没有编译错误。
但是,以下原因导致相同的编译错误:
class Tree<TREE extends Tree<?,?>, DATA> {
public Tree(Class<Tree<?,?>> clazz) { // changed
System.out.println(this.getClass());
System.out.println(clazz);
System.out.println();
if (this.getClass() != clazz)
throw new RuntimeException();
}
}
Tree<Tree<?,?>, String> tree01a = new Tree<Tree<?,?>, String>(Tree.class);
// The constructor Tree<Tree<?,?>,String>(Class<Tree>) is undefined
根据下面的my comment,我尝试了这个。希望它有助于一些灵感。
static class SimpleClass<T> {
private SimpleClass(Object dummy) {
// dummy constructor, avoid recursive call of the default constructor
}
SimpleClass() {
SimpleClass<T> myself = new SimpleClass<T>(new Object()) {};
System.out.println(((ParameterizedType) myself.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
// prints "T"
TypeReference<SimpleClass<T>> typeRef = new TypeReference<SimpleClass<T>>() {};
System.out.println(typeRef.getType());
// prints "Main.Main$SimpleClass<T>"
}
void func() {
SimpleClass<T> myself = new SimpleClass<T>(new Object()) {};
System.out.println(((ParameterizedType) myself.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
// prints "T"
TypeReference<SimpleClass<T>> typeRef = new TypeReference<SimpleClass<T>>() {};
System.out.println(typeRef.getType());
// prints "Main.Main$SimpleClass<T>"
}
}
public static void main(String[] args) {
SimpleClass<String> simpleObj = new SimpleClass<String>();
simpleObj.func();
SimpleClass<String> outsideSimpleClass = new SimpleClass<String>(){};
System.out.println(((ParameterizedType) outsideSimpleClass.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
// prints "class java.lang.String"
}
请注意,我们无法获取“类java.lang.String”内部 SimpleClass
。
更重要的是,如果我们使用Type Argument <T>
来实例化另一个类中的对象,我们仍然无法从中获取type参数:
static class AnotherClass<T> {
private AnotherClass(Object dummy) {}
}
static class SimpleClass<T> {
SimpleClass() {
AnotherClass<T> another = new AnotherClass<T>(new Object()) {};
System.out.println(((ParameterizedType) another.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
// prints "T"
TypeReference<AnotherClass<T>> anotherTypeRef = new TypeReference<AnotherClass<T>>() {};
System.out.println(anotherTypeRef.getType());
// prints "Main.Main$AnotherClass<T>"
}
void func() {
AnotherClass<T> another = new AnotherClass<T>(new Object()) {};
System.out.println(((ParameterizedType) another.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
// prints "T"
TypeReference<AnotherClass<T>> anotherTypeRef = new TypeReference<AnotherClass<T>>() {};
System.out.println(anotherTypeRef.getType());
// prints "Main.Main$AnotherClass<T>"
}
}
请注意,这意味着AnotherClass
的类型参数无法在SimpleClass
,中显示,因为它是类本身以外的地方!
据我了解,我们只能使用匿名子类&amp; getGenericSuperclass()
技巧在一个实际上已经知道答案的地方。例如在main()
中,这里是class java.lang.String
实际定义为Type Argument的地方。
(IMO,如果这个技巧的能力如此受限制,它根本就没用。)
答案 0 :(得分:0)
为此查看TypeTools。例如:
List<String> stringList = new ArrayList<String>() {};
Class<?> stringType = TypeResolver.resolveRawArgument(List.class, stringList.getClass());
assert stringType == String.class;