java - Java 的类型参数通配符到底是什么意思? Foo 和 Foo<?> 之间的真正区别是什么?

标签 java generics jakarta-ee types

对于通用接口(interface):

public interface Foo<T> {
    void f(T t); 
} 

两个字段的区别:

public class Bar {
    Foo foo1; 
    Foo<?> foo2; 
}

foo2吗是一个通用类型并且 foo不是。自 ?是一个通配符(我认为这意味着任何类型)并且每种类型都是 Object 的子类型,那么我希望 Foo<?>Foo<Object>在语义和句法上等价。

但是,请检查以下内容:

public class Puzzler {
    void f() {
        Integer i = null; 
        Foo<?> foo1 = null;
        foo1.foo(i); // ERROR 
        Foo foo2 = null; 
        foo2.foo(i); // OKAY
        Foo<Integer> foo3 = null; 
        foo3.foo(i); // OKAY 
        Foo<Object> foo4 = null; 
        foo4.foo(i); // OKAY
    }

    private interface Foo<T> {
        void foo(T t);
    } 
}

所以 Foo<?>Foo<Object>在句法上相同。

这是怎么回事?我很难理解这一点。

最佳答案

Foo<?>在语义上与 Foo<? extends Object> 相同: 这是一个 Foo带有特定类型的参数,但关于“某物”的唯一已知信息是它是 Object 的某个子类(这并没有说太多,因为所有类都是 Object 的子类)。 Foo<Object> ,另一方面,是一个 Foo特别是类型参数 Object .虽然一切都与 Object 分配兼容, 并非所有内容都与 ? 兼容其中 ?延伸Object .

这是一个为什么 Foo<?> 的例子应该产生一个错误:

public class StringFoo implements Foo<String> {
    void foo(String t) { . . . }
}

现在将您的示例更改为:

Foo<?> foo1 = new StringFoo();

i是一个 Integer , 编译器不可能允许 foo1.foo(i)编译。

注意

Foo<Object> foo4 = new StringFoo();

也不会根据 matching parameterized types 的规则进行编译自 ObjectString是可证明的不同类型。

Foo (根本没有类型参数——原始类型)通常应被视为编程错误。根据Java Language Specification (§4.8) ,但是,编译器接受此类代码是为了不破坏非通用的遗留代码。

因为type erasure ,这对生成字节码没有任何影响。也就是说,它们之间的唯一区别在于编译时。

关于java - Java 的类型参数通配符到底是什么意思? Foo 和 Foo<?> 之间的真正区别是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9594753/

相关文章:

java - srcs 和非 srcs jar 之间的区别?

swift - 具有通用协议(protocol)的 VIPER 架构

java - NetBeans 8.2 - Weblogic - Ant 构建

jakarta-ee - @Singleton bean 初始化失败,因为不是预期的事务状态

java - 查找网格中与给定矩形相交的单元格

java - IndexOutOfBounds 异常 Java String 类 charAt 方法

generics - Hamcrest 的任何东西()都无法编译

java - 在使用 Java 泛型方面需要一些帮助

performance - OpenEJB 性能最高、最轻量的传输是什么?

java - 运行配置中的 Eclipse Maven 依赖项?