tags:

views:

643

answers:

5

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 '?'.

So what's the difference between:

HashMap<String, ?> hash1;

and

HashMap<String, Object> hash2;
+1  A: 

See the official tutorial on Wildcards. It explains it well and gives an example of why it's necessary over simply using Object.

Ben S
+11  A: 

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 Strings to anything: If you would write

public void foobar(Map<String, Object> ms) {
    ...
}

you can't supply a HashMap<String, String>. If you write

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)).

Sample: If you'd like to write a method that accepts Lists of InputStreams and subtypes of InputStream, you'd write

public void foobar(List<? extends InputStream> ms) {
    ...
}

By the way: Joshua Bloch's Effective Java is an excellent resource when you'd like to understand the not so simple things in Java. (Your question above is covered very good in the book aswell.)

Johannes Weiß
+2  A: 

You can't safely put anything into Map<String, ?>, because you don't know what type the values are supposed to be.

You can put any object into a Map<String, Object>, because the value is known to be an Object.

erickson
"You can't safely put anything into Map<String, ?>" False. You CAN, that's its purpose.
Ben S
Wrong, Ben. Doing this will produce "unchecked" warnings. The purpose of wildcards is to write code that can operate on any generic type.
erickson
Ben is wrong, the only value you can put into a collection of type <?> is null, whereas you can put anything into a collection of type <Object>.
sk
From the link I gave in my answer: "Since we don't know what the element type of c stands for, we cannot add objects to it.". I apologize for the misinformation.
Ben S
+2  A: 

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.

grigory
There's a point to be made that this isn't exactly easy ;-), but it is right.
Sean Reilly
A: 

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:

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.

and the wild card may start making more sense, hopefully.

Julien Chastang
If "?" confuses you, "? extends Object" will likely confuse you more. Maybe.
Michael Myers
Trying to provide "thinking tools" to allow one to reason about this difficult subject. Provided additional info on extending wildcards.
Julien Chastang
Thanks for the additional info. I'm still digesting it. :)
skiphoppy