package ir.openuniverse;
public class Main {
public static void main(String[] args) throws NoSuchFieldException {
System.out.println(A.class.getField("t").getType().getName());
}
}
class A extends B<D> {}
class B<T extends C> {
public T t;
}
class C {}
class D extends C {}
输出为ir.openuniverse.C
。 为什么?我希望有D
!
编辑:
此问题与解决方法或替代方法无关。因此,答案与解决方法无关。有关其他方法,请参见下面的myself answer。
答案 0 :(得分:5)
发生这种情况是由于type erasure。
Java将您的泛型类B<T>
编译为字节代码,适合与所有可以引用它的类一起使用,包括可能扩展了B<T>
的任何类。
由于T
仅限于扩展C
的类,因此Java知道您可以分配B.t
的任何值都将扩展C
,因此它将类编译成等效的类
class B {
C t;
}
此时,t
的任何分配都可以使用;不过,从t
读取将产生C
,因此编译器必须做一些“魔术”来解决此问题。具体地说,编译器在已知子类型的地方插入类型强制转换。如有必要,它可能还会生成 bridge方法。有关详细信息,请参见答案顶部的链接。
答案 1 :(得分:1)
在编译过程中,Java的类型擦除更改
contentView
至:
contentView.addSubview(rankingLabel)
contentView.addConstraints(cellConstraints)
由于class B<T extends C> {
public T t;
}
标识了字段的声明类型,所以输出为class B<C> {
public C t;
}
答案 2 :(得分:0)
感谢大家的帮助。最后,我不得不将A
的定义更改为:
class A extends B<D> {
public D t;
}
满足我的目的就足够了(尽管我一点都不喜欢它!)。
编辑:
上述方法不是基本方法。请参阅下面的 @DanielPryden 的前两个注释。
替代解决方法:
class A extends B<D> {
@Override public D getT() { return super.getT(); }
}
class B<T extends C> {
private T t;
public T getT() { return t; }
}
在main()
中:
System.out.println(A.class.getMethod("getT").getReturnType().getName());
输出:ir.openuniverse.D
另一种方式:
注意:这不是解决主要问题的方法(请参见下面的 @DanielPryden 的第四条评论)。但是也许可以帮助您(像我一样)。
当您至少有一个A
实例时,可以使用此解决方法:
public class Main {
public static void main(String[] args) {
A a = new A();
System.out.println(a.t.getClass().getName());
// Or via reflection:
// System.out.println(a.getClass().getField("t").get(a).getClass().getName());
}
}
class A extends B<D> {
{ t = new D(); }
}
class B<T extends C> {
public T t;
}
输出:ir.openuniverse.D