之间有什么区别?和 Java 泛型中的对象?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/678822/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the difference between ? and Object in Java generics?
提问by skiphoppy
I'm using Eclipse to help me clean up some code to use Java generics properly. Most of the time it's doing an excellent job of inferring types, but there are some cases where the inferred type has to be as generic as possible: Object. But Eclipse seems to be giving me an option to choose between a type of Object and a type of '?'.
我正在使用 Eclipse 来帮助我清理一些代码以正确使用 Java 泛型。大多数情况下,它在推断类型方面做得非常出色,但在某些情况下,推断类型必须尽可能通用:Object. 但是 Eclipse 似乎给了我一个选项,可以在 Object 类型和 '?' 类型之间进行选择。
So what's the difference between:
那么有什么区别:
HashMap<String, ?> hash1;
and
和
HashMap<String, Object> hash2;
采纳答案by Johannes Weiss
An instance of HashMap<String, String>
matches Map<String, ?>
but not Map<String, Object>
. Say you want to write a method that accepts maps from String
s to anything: If you would write
HashMap<String, String>
匹配Map<String, ?>
但不匹配的实例Map<String, Object>
。假设你想写一个方法来接受从String
s 到任何东西的映射:如果你写
public void foobar(Map<String, Object> ms) {
...
}
you can't supply a HashMap<String, String>
. If you write
你不能提供一个HashMap<String, String>
. 如果你写
public void foobar(Map<String, ?> ms) {
...
}
it works!
有用!
A thing sometimes misunderstood in Java's generics is that List<String>
is not a subtype of List<Object>
. (But String[]
is in fact a subtype of Object[]
, that's one of the reasons why generics and arrays don't mix well. (arrays in Java are covariant, generics are not, they are invariant)).
在 Java 的泛型中有时会被误解的一件事是它List<String>
不是List<Object>
. (但String[]
实际上是 的子类型Object[]
,这就是泛型和数组不能很好混合的原因之一。(Java 中的数组是协变的,泛型不是,它们是不变的))。
Sample:
If you'd like to write a method that accepts List
s of InputStream
s and subtypes of InputStream
, you'd write
示例:如果您想编写一个接受List
s 的InputStream
s 和 的子类型的方法InputStream
,您可以编写
public void foobar(List<? extends InputStream> ms) {
...
}
By the way: Joshua Bloch's Effective Javais an excellent resource when you'd like to understand the not so simple things in Java. (Your question above is also covered very well in the book.)
顺便说一句:Joshua Bloch 的 Effective Java是一个很好的资源,当您想了解 Java 中不那么简单的事情时。(你上面的问题在书中也有很好的介绍。)
回答by erickson
You can't safely put anything into Map<String, ?>
, because you don't know what type the values are supposed to be.
您不能安全地将任何内容放入Map<String, ?>
,因为您不知道这些值应该是什么类型。
You can put any object into a Map<String, Object>
, because the value is known to be an Object
.
您可以将任何对象放入 a 中Map<String, Object>
,因为已知值是 an Object
。
回答by topchef
It's easy to understand if you remember that Collection<Object>
is just a generic collection that contains objects of type Object
, but Collection<?>
is a super type of all types of collections.
如果您还记得它Collection<Object>
只是一个包含 type 对象的泛型集合,则很容易理解Object
,但它Collection<?>
是所有类型集合的超类型。
回答by Julien Chastang
Another way to think about this problem is that
考虑这个问题的另一种方式是
HashMap<String, ?> hash1;
is equivalent to
相当于
HashMap<String, ? extends Object> hash1;
Couple this knowledge with the "Get and Put Principle" in section (2.4) from Java Generics and Collections:
将此知识与Java 泛型和集合(2.4) 节中的“获取和放置原则”结合起来:
The Get and Put Principle: use an extends wildcard when you only get values out of a structure, use super wildcard when you only put values into a structure, and don't use a wildcard when you both get and put.
Get 和 Put 原则:当你只从结构中获取值时使用扩展通配符,当你只将值放入结构时使用超级通配符,当你同时获取和放置时不要使用通配符。
and the wild card may start making more sense, hopefully.
外卡可能会开始变得更有意义,希望如此。
回答by Eyal
The answers above covariance cover most cases but miss one thing:
以上协方差的答案涵盖了大多数情况,但遗漏了一件事:
"?" is inclusive of "Object" in the class hierarchy. You could say that String is a type of Object and Object is a type of ?. Not everything matches Object, but everything matches ?.
“?” 包括类层次结构中的“对象”。你可以说 String 是 Object 的类型,Object 是 ? 的类型。并非所有内容都匹配 Object,但所有内容都匹配 ?。
int test1(List<?> l) {
return l.size();
}
int test2(List<Object> l) {
return l.size();
}
List<?> l1 = Lists.newArrayList();
List<Object> l2 = Lists.newArrayList();
test1(l1); // compiles because any list will work
test1(l2); // compiles because any list will work
test2(l1); // fails because a ? might not be an Object
test2(l2); // compiled because Object matches Object
回答by Kr?w
Declaring hash1
as a HashMap<String, ?>
dictates that the variable hash1
can hold any HashMap
that has a key of String
and any type of value.
声明hash1
为 aHashMap<String, ?>
表示该变量hash1
可以保存任何HashMap
具有键的String
和任何类型的值。
HashMap<String, ?> map;
map = new HashMap<String, Integer>();
map = new HashMap<String, Object>();
map = new HashMap<String, String>();
All of the above is valid, because the variablemap
can store any of those hash maps. That variable doesn't care what the Value type is, of the hashmap it holds.
以上所有都是有效的,因为变量map
可以存储任何这些哈希映射。该变量不关心它持有的哈希映射的值类型是什么。
Having a wildcard does not, however, let you put any type of object into your map. as a matter of fact, with the hash map above, you can't put anything into it using the map
variable:
有一个通配符也没有,但是,让你把任何类型的对象到您的地图。事实上,使用上面的哈希映射,您不能使用map
变量将任何内容放入其中:
map.put("A", new Integer(0));
map.put("B", new Object());
map.put("C", "Some String");
All of the above method calls will result in a compile-time error because Java doesn't know what the Value type of the HashMap inside map
is.
以上所有方法调用都会导致编译时错误,因为Java不知道里面的HashMap的Value类型map
是什么。
You can still get a value out of the hash map. Although you "don't know the value's type," (because you don't know what type of hash map is inside your variable), you can say that everything is a subclass of Object
and, so, whatever you get out of the map will be of the type Object:
您仍然可以从哈希映射中获取一个值。尽管您“不知道值的类型”(因为您不知道变量中的哈希映射类型是什么),但您可以说所有内容都是Object
and的子类,因此,无论您从映射中得到什么将是对象类型:
HashMap<String, Integer> myMap = new HashMap<>();// This variable is used to put things into the map.
myMap.put("ABC", 10);
HashMap<String, ?> map = myMap;
Object output = map.get("ABC");// Valid code; Object is the superclass of everything, (including whatever is stored our hash map).
System.out.println(output);
The above block of code will print 10 to the console.
上面的代码块将在控制台打印 10。
So, to finish off, use a HashMap
with wildcards when you do not care (i.e., it does not matter) what the types of the HashMap
are, for example:
因此,最后,HashMap
当您不关心(即无关紧要)的类型是什么时,请使用带有通配符的a HashMap
,例如:
public static void printHashMapSize(Map<?, ?> anyMap) {
// This code doesn't care what type of HashMap is inside anyMap.
System.out.println(anyMap.size());
}
Otherwise, specify the types that you need:
否则,请指定您需要的类型:
public void printAThroughZ(Map<Character, ?> anyCharacterMap) {
for (int i = 'A'; i <= 'Z'; i++)
System.out.println(anyCharacterMap.get((char) i));
}
In the above method, we'd need to know that the Map's key is a Character
, otherwise, we wouldn't know what type to use to get values from it. All objects have a toString()
method, however, so the map can have any type of object for its values. We can still print the values.
在上面的方法中,我们需要知道 Map 的键是 a Character
,否则,我们不知道使用什么类型从中获取值。toString()
然而,所有对象都有一个方法,因此映射可以为它的值使用任何类型的对象。我们仍然可以打印这些值。