user2684215
user2684215

Reputation: 73

Generics can't instantiate `new HashMap<String, ?>`. Why?

Why does the following line of code give an error in HashMap? It is not taking the wild card in the right hand side of the assignment.

Map<String,?> map=new HashMap<String,?>();

Upvotes: 1

Views: 9147

Answers (6)

Hazok
Hazok

Reputation: 5593

In Java 7 and later you could just used the diamond notation as mentioned here:

https://docs.oracle.com/javase/tutorial/java/generics/types.html#diamond

Here's a quick example of using the diamond derived from the line of code shown in the question:

Map<String,?> map=new HashMap<>();

Upvotes: 1

newacct
newacct

Reputation: 122518

Just do:

class SuperBogusUnrelatedClass {}
// ...
Map<String, ?> map = new HashMap<String, SuperBogusUnrelatedClass>();

The above is correct, and 100% type-safe. Seriously, you can just put anything in there, even Math. Why is it correct? Since it's a wildcard, it means it can be anything; you don't know what it is.

The ridiculousness of the above example also shows why this initialization is pretty much completely useless -- since the type parameter is unknown, you can't safely put any values (except null) into the Map<String, ?>. So your Map will either have to be empty, or filled with entries whose value is null. So basically, it is equivalent to a Set.

Upvotes: 4

Rohit Jain
Rohit Jain

Reputation: 213391

You can't instantiate a parameterized type like that. A wildcard parameterized type is not a concrete type, so they could not appear in a new expression.

A wildcard parameterized type denotes a family of types comprising concrete instantiations of a generic type. The kind of the wildcard being used determines which concrete parameterized types belong to the family.

So, Map<String,?> denotes the family of types, which can be Map<String, Object>, Map<String, String>, anything. You have to use the concrete type while creating an actual map.

So, you can do:

Map<String,?> map=new HashMap<String, String>();
Map<String,?> map=new HashMap<String, Object>();

But the issue with this declaration is that, you can't add anything to map except null.


On the other hand, consider other types of wildcard - upper bounded, and lower bounded.

Upper Bounded Wildcard:

Map<String, ? extends Number>

The family of types denoted by this type are the concrete instantiation, where the value type is either Number, or a subtype of Number. So, for this one, the following are valid creation of concrete parameterized type:

Map<String, ? extends Number> map = new HashMap<String, Number>();
Map<String, ? extends Number> map = new HashMap<String, Integer>();

But again, issue here is you can't add anything in the map except null or the value previously fetched from it.


Lower Bounded wildcard:

Map<String, ? super Integer>

As you already know, you can't add anything to the wildcard parameterized type with unbounded wildcard, or upper bounded wildcard. There is a third type - lower bounded wildcard, which can be used if you are going to add something to the map. The family of type for the above parameterized type are the one that takes value of type Integer or it's super type. So, you can instantiate it like this:

Map<String, ? super Integer> map = new HashMap<String, Number>();
Map<String, ? super Integer> map = new HashMap<String, Integer>();
Map<String, ? super Integer> map = new HashMap<String, Serializable>();

But there is another issue here. Although you can add a value to it, but when you fetch some value, you cannot be sure what type you get.


So, depending upon your requirement, you may have to use one or the other type of wildcard. May be some more information in the question might help you. But, in general just remember, you can't create an object of wildcard parameterized type, but only concrete parameterized type.

Upvotes: 18

Aniket
Aniket

Reputation: 379

You can not use a wild card while instantiating an object of a concrete class.

Upvotes: 2

Prabhaker A
Prabhaker A

Reputation: 8483

You are instantiating an object by whose type is a type parameter.It is not possible.
because the compiler does not know how to create objects of an unknown type.
More details Can I create an object whose type is a type parameter?

Upvotes: 0

Code-Apprentice
Code-Apprentice

Reputation: 83577

Since you are creating a HashMap object, you must specify all of the generic parameters.

Upvotes: 1

Related Questions