19

<?>无界通配符 eg和有界通配符Objecteg之间有区别<? extends Object>吗?

我记得在某处读过,泛型的早期草案有所不同,但再也找不到那个来源了。

4

6 回答 6

32

从实用的角度来看,对大多数人来说,<? extends Object>是一样的<?>,就像每个人在这里建议的那样。

但是,它们在两个非常细微的点上有所不同:

  1. JVMS(Java 虚拟机规范)对无界通配符有一个特殊规范,ClassFileFormat-Java5指定无界通配符编码为*,而将对象有界通配符编码为+Ljava/lang/Object;。此类更改将通过任何分析字节码的库泄漏。编译器编写者也需要处理这个问题。从修订到“类文件格式”

  2. 从可重复性的角度来看,这些是不同的。 JLS 4.6 和 4.7List<?>编码为可具体化类型,但List<? extends Object>作为擦除类型。任何添加的库编写者.isReifiable()(例如mjc lib)都需要考虑到这一点,以遵守 JLS 术语。从JLS 4.6 和 4.7

于 2010-01-06T21:28:19.323 回答
19

作为 pedntry 的一点,如果类/接口/构造函数/方法声明了一个边界(除了extends Object),那是有区别的。

interface Donkey<T extends Thing> { }

...
    Donkey<? extends Object> foo; // FAIL
于 2010-01-07T01:03:54.677 回答
4

例如,从实验看来,List<?>andList<? extends Object>是两种方式的分配兼容,并且使用其中一种方式具有签名的方法可以被使用另一种方式的签名覆盖。例如,

import java.util.List;

class WildcardTest<T> {
    public void foo(List<? extends T> bar) {}
}

class WildcardTest2 extends WildcardTest<Object> {
    @Override
    public void foo(List<?> bar) {super.foo(bar);}
}
于 2010-01-06T20:44:11.083 回答
2

这很复杂...

对于任何类型变量T,规范说http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.4

每个类型变量...都有一个界限。如果没有为类型变量声明边界,则假定为 Object。

有人会认为通配符也是如此,?应该只是? extends Object.

然而,通过规范搜索,根本没有证据表明通配符必须具有上限(或下限)。“无界”?始终与有界通配符区别对待。

我们可以从子类型化规则中推断,List<?>List<? extends Object>是彼此的子类型,即它们基本上是相同的类型。

但是规范仍然将它们分开处理。例如http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.7 List<?>是可具体化的类型,但List<? extends Object>不是,这意味着

    // ok
    List<?>[] xx = {};
    // fail
    List<? extends Object>[] yy = {};

    // ok
    boolean b1 = (y instanceof List<?>);
    // fail
    boolean b2 = (y instanceof List<? extends Object>);

我不明白为什么。说通配符必须有一个上限和一个下限似乎完全没问题,默认为Objectand null type

于 2013-01-15T22:23:03.680 回答
-1

Java 中的所有内容除了基元外都扩展了 Object,所以不,没有区别。自动装箱允许使用原语,因此可以说 java 中的一切都是对象。

于 2010-01-06T20:38:01.307 回答
-1

<? extends Object>与 完全相同<?>。很抱歉,我手边没有参考资料,但是……它是。:)

编辑:当然,当我这么说时,我只是从一个特定的角度思考。忽略我的答案(这是完全正确的低估)并查看真实故事的评分较高的答案。

于 2010-01-06T21:04:29.613 回答