【问题标题】:Generics wildcard instantiation泛型通配符实例化
【发布时间】:2012-10-06 16:21:35
【问题描述】:

前几天我在审查别人的代码时遇到了一条引起一些担忧的行。为了简化,假设我有一个泛型 A 类和一个抽象 B 类。是否允许以下​​实例化,如果允许,为什么?

Object obj = new A<? extends B>();

我个人从未见过像上面这样的实例化,尽管有这样的声明

A<? extends B> obj = null;

肯定会成立。我一直在泛型中使用通配符来声明方法参数,所以我可能没有经验。

【问题讨论】:

标签: java generics wildcard declaration instantiation


【解决方案1】:

其实new A&lt;? extends B&gt;() 不会编译。自 Java 5 以来,它一直是非法的。

但我猜您的原始示例类似于new A&lt;X&lt;? extends B&gt;&gt;()。后者在最近的 Java 版本中是合法的。

这个想法是,当实例化一个对象时,类型参数的值可以是任何非通配符类型。 ? extends B 是通配符类型,因此不允许使用。但是X&lt;? extends B&gt; 不是通配符类型,尽管它具有 通配符类型作为组件。所以你可以合法地打电话给new A&lt;X&lt;? extends B&gt;&gt;()。

如果您以这种方式考虑,这些规则是有意义的。归根结底,像? extends B 这样的通配符类型不能是字段或变量的已声明 类型,这是更基本规则的副产品。如果A 定义为

class A<T> {
    T value;
}

那么假设的new A&lt;? extends B&gt;().value 将是一个声明类型 ? extends B 的字段。既然这是非法的,那么实例化也是如此。但是new A&lt;X&lt;? extends B&gt;&gt;() 没有这个问题。

【讨论】:

  • 相当好的答案,但我认为后半部分的推理没有多大意义。如果变量a 被键入为A&lt;? extends B&gt;,这并不意味着a.value 被声明为? extends B - value 被声明为T 其中A 声明@987654340 @。 a.value 确实 评估 到 ? extends B。请参阅我对类似问题的回答here。
  • @PaulBellora 承认,我在第二部分不是很清楚。我想说的是,表达式 a.value 的推定类型和变量 a.value 的声明类型之间存在差异。请注意,变量既是 r 值又是 l 值,因此如果您允许创建具有通配符类型 ? extends T(或 ? super T)的变量/字段,它将是一个固有的障碍变量。您将无法将其用作 r 值(分别为 l 值)。现在,对于普通参考 a 来说这是可以容忍的,但对于 this 来说绝对不行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-03
  • 2011-04-02
  • 2022-01-18
  • 1970-01-01
相关资源
最近更新 更多