Java 什么';这是原始类型、无界通配符和在泛型中使用对象之间的区别
我正在阅读关于有效Java中泛型的一章 请帮助我了解Java 什么';这是原始类型、无界通配符和在泛型中使用对象之间的区别,java,generics,effective-java,Java,Generics,Effective Java,我正在阅读关于有效Java中泛型的一章 请帮助我了解Set、Set和Set之间的区别 以下段落摘自此书 快速回顾一下,Set是一种参数化类型,表示 可以包含任何类型对象的集合,set是通配符类型 表示只能包含某些未知对象的集合 类型,Set是一个原始类型,它从泛型类型中选择 系统 “未知类型”是什么意思?类型对象的所有未知类型是否都是?在这种情况下,Set和Set之间的具体区别是什么?在Set和Set之间的区别是Set类型的变量可以指定一个更具体的泛型,如: Set<?> set =
Set
、Set
和Set
之间的区别
以下段落摘自此书
快速回顾一下,Set
是一种参数化类型,表示
可以包含任何类型对象的集合,set
是通配符类型
表示只能包含某些未知对象的集合
类型,Set
是一个原始类型,它从泛型类型中选择
系统
“未知类型”是什么意思?类型
对象的所有未知类型是否都是?在这种情况下,Set
和Set
之间的具体区别是什么?在Set
和Set
之间的区别是Set
类型的变量可以指定一个更具体的泛型,如:
Set<?> set = new HashSet<Integer>();
Set Set=newhashset();
而Set
只能分配Set
:
Set Set=newhashset();//不会编译
集合
仍然有用,因为任何对象都可以放入其中。从这个意义上讲,它很像原始的集合
,但在泛型类型系统中工作得更好。
- 原始类型(
Set
)将该类型视为完全没有泛型类型信息。请注意,这种微妙的影响不仅会忽略类型参数T
,还会忽略该类型的方法可能具有的所有其他类型参数。您可以向它添加任何值,它将始终返回Object
Set
是一个集合
,它接受所有对象
对象(即所有对象),并返回类型为对象
的对象
Set
是一个Set
,它接受某些特定但未知类型的所有对象,并将返回该类型的对象。由于对该类型一无所知,因此无法向该集合添加任何内容(除了null
),并且您只知道它返回的值是对象的某个子类型
设置
:这里没有泛型,不安全。添加您想要的内容
Set
:我们在范围内不知道的某种类型的集合。与运行时的Set相同,由于类型擦除,JVM只会看到Set
在编译时,有一个区别:
Set
使用Object
参数化类型E
,因此,Set.add(E元素)
将参数化为Set.add(Object元素)
Set
另一方面,在类型E
上添加通配符,因此Set.add(E元素)
被转换为Set.add(?.element)
。因为这是不可编译的,所以java将其“翻译”为Set.add(null元素)
。这意味着您不能向该集合添加任何内容(空值除外)。原因是通配符引用的是未知类型 Set Set=newhashset();
Set<?> set = new HashSet<String>();
set.add(new Object()); // compile time error
set.add(新对象());//编译时错误
因为我们不知道set的元素类型代表什么,所以我们不能添加对象
去吧。add()
方法采用E
类型的参数,即集合的元素类型。
当实际类型参数为?
时,它表示某个未知类型。任何
我们传递给add的参数必须是此未知类型的子类型。自从我们
不知道那是什么类型的,我们不能传递任何信息。唯一的例外是
null
,它是每种类型的成员
给定一个集合
,我们可以调用get()
并使用结果。结果类型是
未知类型,但我们始终知道它是一个对象。因此,安全地
将get()
的结果分配给Object
类型的变量,或将其作为参数传递
其中需要类型对象
“未知类型”是什么意思
确切的意思是,集合
有一些通用参数,但我们不知道它是什么
因此,分配给集合
变量的集合可能是集合
,或集合
,或集合
或包含任何其他特定类型的集合
那么这对你如何使用它意味着什么呢?嗯,从中得到的任何东西都将是?
,不管是什么。因为我们不知道类型参数是什么,所以您不能说任何比集合的元素将可分配给对象更具体的事情(只是因为所有类都是从它扩展而来的)
如果您正在考虑向集合中添加某些内容,add
方法将采用?
(这很有意义,因为这是集合中的对象类型)。但是,如果您尝试添加任何特定对象,如何确保这是类型安全的?你不能-如果你正在插入一个字符串,你可能会把它放到一个集合中,例如,这会破坏你从泛型中获得的类型安全性。因此,虽然您不知道泛型参数的类型,但不能提供这种类型的任何参数(除了null
,因为这是任何类型的“实例”)
与大多数与泛型相关的答案一样,本文将重点放在集合上,因为它们更容易本能地理解。但是,参数适用于任何接受泛型参数的类-如果它是用无界通配符参数?
声明的,则不能向它提供任何参数,并且您收到的任何类型的值都只能分配给对象
我向我的朋友解释此项,并特别要求“safeAdd”方法作为unsafeAdd示例的计数器
public static void main(String[] args) {
List<String> strings = new ArrayList<String>();
unsafeAdd(strings, new Integer(42)); // No compile time exceptions
// New
safeAdd(strings, new Integer(42)); // Throwing an exception at compile time
String s = strings.get(0); // Compiler-generated cast
}
private static void unsafeAdd(List list, Object o) {
list.add(o);
}
private static <E> void safeAdd(List<E> list, E o) {
list.add(o);
}
publicstaticvoidmain(字符串[]args){
列表字符串=新Arr
public static void main(String[] args) {
List<String> strings = new ArrayList<String>();
unsafeAdd(strings, new Integer(42)); // No compile time exceptions
// New
safeAdd(strings, new Integer(42)); // Throwing an exception at compile time
String s = strings.get(0); // Compiler-generated cast
}
private static void unsafeAdd(List list, Object o) {
list.add(o);
}
private static <E> void safeAdd(List<E> list, E o) {
list.add(o);
}
// Would only print objects of type 'Object'
public static void printList(List<Object> list) {
for (Object elem : list)
System.out.println(elem + " ");
System.out.println();
}
// The type would really depend on what is being passed
public static void printList(List<?> list) {
for (Object elem: list)
System.out.print(elem + " ");
System.out.println();
}