当前位置: 首页 > 面试题库 >

java.lang.Class泛型和通配符

尉迟鸿熙
2023-03-14
问题内容

为什么以下代码无法编译?

interface Iface<T> { }

class Impl<T> implements Iface<T> { }

class TestCase {
    static Class<? extends Iface<?>> clazz = Impl.class;
}

错误是

java:不兼容的类型:java.lang.Class<Impl>无法转换为java.lang.Class<? extends Iface<?>>

但我不明白为什么不捕获通配符。


问题答案:

这里的子类型关系为:

          Class<? extends Iface>
           ╱                  ╲
Class<? extends Iface<?>>   Class<Impl>

(我在回答“无法从转换List<List>为List<List<?>>”中解释了这一点。)

因此,基本上它不会编译,因为它是横向转换。

如果可能的话,您可以执行我在那边描述的转换:

(Class<? extends Iface<?>>)(Class<? extends Impl>)Impl.class

如果您无法进行转换,则可能只需要处理raw bound即可Class<? extends Iface>。主要由于警告而令人讨厌,但它打开了发生错误的可能性:

interface Iface<T> {
    void accept(T a);
}

class Impl2 implements Iface<String> {
    public void accept(String a) { }
}

class TestCase {
    static Class<? extends Iface> clazz = Impl2.class;

    public static void main(String[] args) throws Exception {
        // throws ClassCastException
        clazz.newInstance().accept(new Object());
    }
}

不太可能发生,但是我想这取决于您在做什么。

我倾向于认为这是Java类型系统的问题。

  • 可能应该有一个特殊的规则,即类型实参? extends T<?>包含类型实参? extends T,例如Class<? extends T>将a 转换为Class<? extends T<?>>。从定义子类型(T是的超类型T<?>)的现有方式的角度来看,这是没有道理的,但从类型安全的角度来看,这是有意义的。

  • 或者,例如List.class应该是Class<List<?>>而不是Class<List>

  • 还是比我聪明的人可以想到的其他一些聪明的东西。

ClassCastException我上面描述的有趣的事情是它是完全人为的。实际上,使用未经检查的强制转换阻止它会发出警告。

我想这只是Java泛型尚未完成的一个信号。



 类似资料:
  • 问题内容: 我试图理解Java泛型,它们似乎很难理解。例如,这很好… …就是这个… … 还有这个 … …但是不能编译: 有人可以用简单的语言解释发生了什么吗? 问题答案: 对于泛型类型,主要要了解的是它们不是协变的。 因此,尽管您可以这样做: 以下内容将无法编译: 这是为了避免您绕过通用类型的情况: 因此,一一讲解您的示例 1个 您的通用方法采用a ,而您采用;(基本上是)。可以分配给类型,并且编

  • 问题内容: 我对Java中的通用通配符有两个疑问: 和之间有什么区别? 什么是有界通配符,什么是无界通配符? 问题答案: 在你的第一个问题中,并且是有界通配符的示例。无限制的通配符看起来像,基本上就是<? extends Object>。宽松地表示泛型可以是任何类型。有界通配符(或)通过说它必须扩展特定类型(称为上限)或必须是特定类型的祖先(称为下限)来对类型进行限制。

  • 所以我在阅读泛型以重新熟悉这些概念,尤其是在涉及通配符的地方,因为我很少使用或遇到通配符。从我的阅读中,我不明白他们为什么使用通配符。下面是我经常遇到的一个例子。 你为什么不这样写: oracle网站上的另一个示例: 为什么这不是写成 我错过什么了吗?

  • 这2个功能有什么区别? 我看到了相同的输出。

  • 问题内容: 您好直接从Oracle http://docs.oracle.com/javase/tutorial/collections/interfaces/collection.html提供的Java教程中 我知道编译时的类型擦除。而且我也知道,一个类型(无界)将被Object取代。知道在编译时如何使用无界通配符进行编译吗?只是删除它,因为它是原始类型? 提前致谢。 问题答案: 假设我们有一个

  • 根据Joshua Bloch的“有效Java”一书,关于如何/何时在泛型中使用有界通配符有一个规则。这个规则就是PECS(productor-extends,Comsumer-Super)。当我研究以下示例时: 根据PECS规则,上述声明是错误的。但是我希望有一个的,并向这个传递一个。为什么不做呢? 为什么要始终使用关键字?为什么使用是错误的? 当然,这也代表了Comsumer的观点。为什么消费者