为什么泛型类型的实例类不同于泛型类型的类?

3

编辑:更简单的例子:

public <T> void shouldBeAbleToGetClassOfT(T t) {
    Class<T> tClass;

    // OK, but shows "unchecked cast" warrning.
    tClass = (Class<T>) t.getClass();

    // Compilation error!
    tClass = t.getClass();
}

类型不兼容。

需要:Class<T>

找到:Class<capture<? extends java.lang.Object>>

我对下面示例中的类型擦除有些困惑:

public static class Example<T> {
    private final T t;

    public Example(final T t) {
        this.t = t;
    }

    public <U extends T> void test(Consumer<T> consumer, U u) {
        // OK, but shows "unchecked cast" warrning.
        consumer.accept((T) t.getClass().cast(u));

        // OK, but shows "unchecked cast" warrning.
        consumer.accept(((Class<T>)t.getClass()).cast(u));

        // Compilation error!
        consumer.accept(t.getClass().cast(u));
    }
}

这里的错误是:

Error:(21, 46) java: 不兼容类型: 无法将java.lang.Object转换为T

这里到底发生了什么?

.getClass() 的返回值被擦除了吗?为什么?

如何最好地处理这个错误?


编辑: 这里是一个更复杂的用例,更接近于我的问题:

public class A<T> {
    private final T t;

    public A(final T t) {
        this.t = t;
    }

    public void printClass() {
        // OK, but shows "unchecked cast" warrning.
        B<T> b = new B<>((Class<T>) t.getClass());

        // Compilation error!
        B<T> b = new B<T>(t.getClass());

        b.printClass();
    }
}

public class B<T> {
    private final Class<T> t;

    public B(final Class<T> t) {
        this.t = t;
    }

    public void printClass() {
        System.out.println(t);
    }
}

4
为什么需要显式类型转换?从编译器的角度来看,U u 已经是一个 T,因为 U 继承自 T。所以一个 Consumer<T> 应该随时接受一个 U!只需删除强制类型转换即可。如果您遇到其他问题,请说明原始问题。 - Nándor Előd Fekete
@NándorElődFekete 为了澄清,我添加了一个更复杂的例子,更接近我的问题。 - Jezor
1个回答

4
getClass文档中得知:
实际结果类型为Class<? extends |X|>,其中 |X| 是调用getClass表达式的静态类型的擦除。 t的静态类型是T,其擦除类型为Object。这意味着t.getClass()的静态类型为Class<? extends Object>,而不是您可能期望的Class<? extends T>
由于t.getClass()的静态类型为Class<? extends Object>,因此编译器只知道t.getClass().cast(u)是一个Object,而不是T。这意味着您无法将其传递给consumer.accept

我明白了。但是你会如何处理这个问题呢?使用@SuppressWarnings注解吗? - Jezor
3
这取决于您实际的使用情况。通常情况下,您甚至不应该处于这种情况; Class.cast 很奇怪并且很少是必需的。在您的示例中,Class.castU 都是多余的。 - user2357112
事实上,实际使用情况要复杂得多,因此我希望尽可能发布最简化的示例。 - Jezor
3
新的例子不是很正确,因为如果tT的子类的实例,那么t.getClass()将是一个Class<SomeSubclass>,而不是一个Class<T>。 但是,如果您更正了这一点,我会说这是一个未经检查的转换和@SuppressWarnings("unchecked")的情况。 - user2357112
3
你可以考虑将 Class<T> 作为一个显式参数传递,而不是调用 getClass(可能会获取子类)。 - user2357112
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接