通配符与类型参数
Wildcard vs TypeParameter
class Employee<T extends Number> { // valid
}
class Employee<? extends Number> { // invalid
}
private static void test(List<? super Number> list1) { // valid
}
private static <T>void test(List<T super Number> list1) { // invalid
}
?
和 T
到底有什么区别,什么时候用什么?
为什么使用 class 定义,?
不起作用,但它适用于 List
,为什么 T
适用于 class 定义,但不适用于List
?
在哪里声明泛型
您不能在引入泛型类型标记之前使用它T
。
在您的方法示例中,您尝试在错误的位置声明 T
,这是无效的语法。得先介绍一下。
然而,对于 class 示例,您已将其放在正确的位置。
在这里您可以在 class 广泛的层面上介绍您的通用类型标记:
public class Foo< HERE > { ... }
这就是你如何为一个方法做的:
public < HERE > void foo(...) { ... }
有界泛型
在这两种情况下,您都可以绑定 T
,例如 T extends Number
,然后相应地使用它:
public class Foo<T extends Number> { ... }
// or
public <T extends Number> void foo(...) { ... }
在你介绍完你的T
之后,你就会像那样使用它。所以List<T>
,举个例子。
public <T extends Number> void foo(List<T> list) { ... }
请注意,T super Number
无效,因为它没有意义,并且不提供比 T
或 Number
或 Object
更多的信息,具体取决于什么你正在努力实现。您可以在 Java generic methods: super can't be used?
阅读更多相关信息
通配符
通配符是另一回事。它们不是您必须首先引入的通用类型标记,例如 T
。相反,他们会阐明您要接受的类型范围。
例如像
这样的方法
public static void foo(List<? super Dog> list) { ... }
可以用 List<Dog>
、List<Animal>
甚至 List<Object>
调用。我们称这样的列表为 consumer of Dog
s。准确地说,这些是 所有可以接受狗的列表,所以 list.add(new Dog())
可以。
另一边,我们有
public static void foo(List<? extends Dog> list) { ... }
可以用 List<Dog>
或 List<Chihuahua>
调用。我们称这样的列表为 Dog
的 生产者 (或提供者)。准确地说,这些是所有可以提供狗的列表。所以 Dog dog = list.get(0)
会起作用。
您可以在 What is PECS (Producer Extends Consumer Super)?
阅读更多关于什么是通配符及其工作原理的详细信息
什么时候使用哪个?
一般来说,当您实际上仍然需要在整个代码中维护类型安全时,您会使用泛型类型标记 T
。 IE。当您需要能够 给类型命名时 。否则你使用通配符 ?
.
例如,假设您要创建一个接受列表和要添加到其中的元素的方法:
public static <T> void addToList(List<T> list, T element) {
list.add(element);
}
你需要引入T
来确保列表的类型匹配给定的元素。否则有人会做你不想要的 addToList(dogs, cat)
。
如果您实际上不需要命名类型,您也可以只使用通配符。例如,一个获取列表并打印其所有内容的方法:
public static void printAll(List<?> list) {
for (Object object : list) {
System.out.println(object);
}
}
class Employee<T extends Number> { // valid
}
class Employee<? extends Number> { // invalid
}
private static void test(List<? super Number> list1) { // valid
}
private static <T>void test(List<T super Number> list1) { // invalid
}
?
和 T
到底有什么区别,什么时候用什么?
为什么使用 class 定义,?
不起作用,但它适用于 List
,为什么 T
适用于 class 定义,但不适用于List
?
在哪里声明泛型
您不能在引入泛型类型标记之前使用它T
。
在您的方法示例中,您尝试在错误的位置声明 T
,这是无效的语法。得先介绍一下。
然而,对于 class 示例,您已将其放在正确的位置。
在这里您可以在 class 广泛的层面上介绍您的通用类型标记:
public class Foo< HERE > { ... }
这就是你如何为一个方法做的:
public < HERE > void foo(...) { ... }
有界泛型
在这两种情况下,您都可以绑定 T
,例如 T extends Number
,然后相应地使用它:
public class Foo<T extends Number> { ... }
// or
public <T extends Number> void foo(...) { ... }
在你介绍完你的T
之后,你就会像那样使用它。所以List<T>
,举个例子。
public <T extends Number> void foo(List<T> list) { ... }
请注意,T super Number
无效,因为它没有意义,并且不提供比 T
或 Number
或 Object
更多的信息,具体取决于什么你正在努力实现。您可以在 Java generic methods: super can't be used?
通配符
通配符是另一回事。它们不是您必须首先引入的通用类型标记,例如 T
。相反,他们会阐明您要接受的类型范围。
例如像
这样的方法public static void foo(List<? super Dog> list) { ... }
可以用 List<Dog>
、List<Animal>
甚至 List<Object>
调用。我们称这样的列表为 consumer of Dog
s。准确地说,这些是 所有可以接受狗的列表,所以 list.add(new Dog())
可以。
另一边,我们有
public static void foo(List<? extends Dog> list) { ... }
可以用 List<Dog>
或 List<Chihuahua>
调用。我们称这样的列表为 Dog
的 生产者 (或提供者)。准确地说,这些是所有可以提供狗的列表。所以 Dog dog = list.get(0)
会起作用。
您可以在 What is PECS (Producer Extends Consumer Super)?
阅读更多关于什么是通配符及其工作原理的详细信息什么时候使用哪个?
一般来说,当您实际上仍然需要在整个代码中维护类型安全时,您会使用泛型类型标记 T
。 IE。当您需要能够 给类型命名时 。否则你使用通配符 ?
.
例如,假设您要创建一个接受列表和要添加到其中的元素的方法:
public static <T> void addToList(List<T> list, T element) {
list.add(element);
}
你需要引入T
来确保列表的类型匹配给定的元素。否则有人会做你不想要的 addToList(dogs, cat)
。
如果您实际上不需要命名类型,您也可以只使用通配符。例如,一个获取列表并打印其所有内容的方法:
public static void printAll(List<?> list) {
for (Object object : list) {
System.out.println(object);
}
}