类和方法签名中的「?」和「T」有什么区别?

22

为什么会出现

public interface ArrayOfONEITEMInterface <T extends ONEITEMInterface>{
    public List<T> getONEITEM();
}

编译,但不运行

public interface ArrayOfONEITEMInterface <? extends ONEITEMInterface>{
    public List<?> getONEITEM();
}

在类和方法签名中,? 和 T 有什么区别?
4个回答

38

?是通配符,表示ONEITEMInterface任何子类,包括它本身。

T在这种情况下是ONEITEMInterface具体实现

由于?是通配符,因此类声明中的?和方法声明中的?之间没有关系,因此它将无法编译。但只有List<?> getONEITEM();可以编译通过。


第一种情况意味着整个类每个实例只能处理Bar类型的一个

interface Foo<T extends Bar> {
     List<T> get();
}

第二种情形允许每个实例Bar任何子类型上运行。

interface Foo {
     List<? extends Bar> get()
}

7
T是一个占位符,由实现或实例化的类提供类型。
?是一个占位符,表示“我不知道或不关心通用类型”,通常在您对容器对象执行的工作不需要知道该类型时使用。
无法在类/接口定义中使用'?',因为值表示占位符的名称(类型将在其他地方提供)。放置'?'没有意义。
此外,占位符不一定是T,它可以是任何标准Java变量。按照惯例,它是一个大写字符,但不必如此。

4

这个语句 <T extends ONEITEMInterface> 声明了一个名为 T 的类型参数。这使得你的泛型类型 ArrayOfONEITEMInterface 可以在其他地方引用该参数。例如,你可以声明像 void add(T t) 这样的方法。

如果不给类型参数命名,你该如何引用它?如果你从未引用过类型参数,那么你的类型为什么要是泛型的呢?例如,你不需要使用参数化类型来执行类似以下操作:

public interface ArrayOfONEITEMInterface {
    List<? extends ONEITEMInterface> getONEITEM();
}

声明匿名类型参数是没有意义的,因此在语法上是不合法的。

如果不给类型参数命名,你会如何引用它?如果你从未引用过类型参数,那么你的类型为什么要是泛型呢?因此,在类声明中的 "?" 和方法返回类型中的 "?" 没有任何关系,所以在类声明中使用 "?" 是没有意义的。这是否意味着在类声明中使用 "?" 总是会导致编译时错误? - ajaysinghnegi
@ajaysinghnegi 在需要a type identifier is required的位置(类声明中类型参数的第一个标记),使用?是非法的,但是?可以出现在该标识符的类型边界中。因此,在class Sample<T extends Comparable<?>中,作为T出现的内容必须是有效的Java标识符,这不包括?,但是在边界extends Comparable<?>中的?是有效的。是的,你说得对,在类声明中的?和方法返回类型中的?是无关的(如果这是合法的话)。 - erickson

4

? 允许您拥有一个未知类型的列表,而 T 则需要确定的类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接