Java 泛型、对象和通配符的区别和说明
Java generics, objects and wildcards differences & clarifications
我想了解这个概念:
T
对象 - 通用,将被擦除为实际类型。
?
对象-将被擦除成什么?
Object
对象;
T
、?
和Object
有什么区别?
我很容易理解#1,但是呢:
Object var;
? var;
两者有什么区别?我读到我不能像 T
或任何其他变量那样显式使用 ?
,并且 ?
与对象相关,而不是类型。
但实际原因是什么?为什么我不能只写 List
个对象 (List<Object>
) 而不是 List
个通配符 (List<?>
)?因为我不知道这两种情况下的对象类型。
另外,我想知道 ?
的擦除是什么?
我将列出 T
和 ?
之间的主要区别:
基本:T
是类型参数,?
是通配符。
含义:T
在定义泛型时用作类型参数class。当您实例化泛型 class 时,T
将被替换为具体类型。
另一方面,当我们想要引用 unknown 类型参数时,我们使用 ?
。
- 定义的地方:如果定义泛型方法,需要在class或方法的顶部声明
T
。您可以在任何地方使用 ?
.
- 映射:每次使用
T
都映射到同一个类型(在同一个class中)。每次使用 ?
都可以映射到不同的类型。
- 对象实例化:您可以使用通用参数
T
创建对象,例如 new ArrayList<T>()
。您不能实例化对象,只能实例化 pointers with ?
.
集合更新:您可以将对象添加到 T
类型的集合中。您不能将对象添加到类型为 ?
的集合中(因为您不知道它的类型)。
类型擦除:对于泛型,类型擦除适用于 use 泛型。当使用泛型时,它们被转换为 compile-time 检查和 execution-time 强制转换。因此,如果您有以下代码,例如:List<String> myList = new ArrayList<String>();
,然后您希望添加到您的列表中,那么您可以执行 myList.add("Hello World");
然后您想要 get
您刚刚添加的项目,方法是执行 String myString = myList.get(0);
然后编译器会将您的代码编译为 List myList = new ArrayList();
和 String myString = (String) myList.get(0);
(add
保持不变,原因很明显)。
所以基本上,在执行时 没有办法 发现 T
本质上是列表对象的 String
(该信息已消失)。
现在对于通配符来说,情况就不同了。通配符 (?
) 被 Object
替换(因为它是 无界的 )。这不是很有用。在 build-time 处,编译器将检查您 仅 调用 Object
的行为。如果你有类似 ? extends Foo
的东西,那么 ?
被替换为它的绑定 Foo
(在 build-time 编译器将检查你是否只传递 Foo
或任何它的子类型(从 Foo
继承的类型)作为参数)。
?
和Object
& T
和Object
的区别可以分别看here and here
我想了解这个概念:
T
对象 - 通用,将被擦除为实际类型。?
对象-将被擦除成什么?Object
对象;
T
、?
和Object
有什么区别?
我很容易理解#1,但是呢:
Object var;
? var;
两者有什么区别?我读到我不能像 T
或任何其他变量那样显式使用 ?
,并且 ?
与对象相关,而不是类型。
但实际原因是什么?为什么我不能只写 List
个对象 (List<Object>
) 而不是 List
个通配符 (List<?>
)?因为我不知道这两种情况下的对象类型。
另外,我想知道 ?
的擦除是什么?
我将列出 T
和 ?
之间的主要区别:
基本:
T
是类型参数,?
是通配符。含义:
T
在定义泛型时用作类型参数class。当您实例化泛型 class 时,T
将被替换为具体类型。 另一方面,当我们想要引用 unknown 类型参数时,我们使用?
。- 定义的地方:如果定义泛型方法,需要在class或方法的顶部声明
T
。您可以在任何地方使用?
. - 映射:每次使用
T
都映射到同一个类型(在同一个class中)。每次使用?
都可以映射到不同的类型。 - 对象实例化:您可以使用通用参数
T
创建对象,例如new ArrayList<T>()
。您不能实例化对象,只能实例化 pointers with?
. 集合更新:您可以将对象添加到
T
类型的集合中。您不能将对象添加到类型为?
的集合中(因为您不知道它的类型)。类型擦除:对于泛型,类型擦除适用于 use 泛型。当使用泛型时,它们被转换为 compile-time 检查和 execution-time 强制转换。因此,如果您有以下代码,例如:
List<String> myList = new ArrayList<String>();
,然后您希望添加到您的列表中,那么您可以执行myList.add("Hello World");
然后您想要get
您刚刚添加的项目,方法是执行String myString = myList.get(0);
然后编译器会将您的代码编译为List myList = new ArrayList();
和String myString = (String) myList.get(0);
(add
保持不变,原因很明显)。
所以基本上,在执行时 没有办法 发现T
本质上是列表对象的String
(该信息已消失)。
现在对于通配符来说,情况就不同了。通配符 (?
) 被Object
替换(因为它是 无界的 )。这不是很有用。在 build-time 处,编译器将检查您 仅 调用Object
的行为。如果你有类似? extends Foo
的东西,那么?
被替换为它的绑定Foo
(在 build-time 编译器将检查你是否只传递Foo
或任何它的子类型(从Foo
继承的类型)作为参数)。
?
和Object
& T
和Object
的区别可以分别看here and here