【问题标题】:Why is the class of instance of generic type not the same as the generic type class?为什么泛型类型实例的类与泛型类型类不一样?
【发布时间】:2016-12-18 01:59:24
【问题描述】:

编辑:更简单的例子:

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

不兼容的类型。

必需:类

找到:类>

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

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

有问题的错误是:

错误:(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);
    }
}

【问题讨论】:

  • 为什么需要显式演员表?从编译器的角度来看,U u 已经是T,因为U extends T,所以Consumer&lt;T&gt; 应该随时接受U!只需删除演员表并感到高兴,或者如果您遇到其他问题,请描述您最初的问题。
  • @NándorElődFekete 进行澄清,我添加了一个更复杂的示例,与我的问题更密切相关。

标签: generics java-8 generic-type-argument


【解决方案1】:

来自getClass 的文档:

实际结果类型为Class&lt;? extends |X|&gt; 其中|X|是调用 getClass 的表达式的静态类型的擦除。

t 的静态类型为T,其擦除为Object。这意味着t.getClass() 具有静态类型Class&lt;? extends Object&gt;,而不是您所期望的Class&lt;? extends T&gt;

由于t.getClass() 具有静态类型Class&lt;? extends Object&gt;,编译器只知道t.getClass().cast(u)Object,而不是T。这意味着您不能将其传递给consumer.accept

【讨论】:

  • 我明白了。你会如何处理这个问题呢? @SuppressWarnings?
  • @Jezor:这取决于您的实际用例。通常,您甚至不应该处于这种情况; Class.cast 很奇怪,很少需要。在您的示例中,Class.castU 都是多余的。
  • 问题是,实际用例要复杂得多,所以我想发布尽可能少的示例。
  • @Jezor:新的例子不太对,因为如果tT 的子类的一个实例,那么t.getClass()Class&lt;SomeSubclass&gt;,而不是@987654344 @。不过,如果您纠正了这一点,我会说这是一个未经检查的演员表和 @SuppressWarnings("unchecked") 的情况。
  • 您也可以考虑将Class&lt;T&gt; 作为显式参数,而不是调用getClass(并可能获得一个子类)。
猜你喜欢
  • 2019-01-20
  • 1970-01-01
  • 1970-01-01
  • 2013-09-18
  • 2013-10-03
  • 2011-04-02
  • 1970-01-01
相关资源
最近更新 更多