Why am I losing type information?

I found something interesting with maps, source codes and generics. The following code:

static { Map map = new HashMap (); Set <Map.Entry> set = map.entrySet (); for (Map.Entry entry : set) {} // fine for (Map.Entry entry : map.entrySet()) {} // compilation error } 

I get a compilation error about type incompatibility, namely: "The object cannot be passed to Entry."

Ideal for convenience

Why entrySet() iterator over entrySet() lose type information if there is no variable that stores it again?

Raw types should not affect the type, so Map.Entry suddenly an object. Or I'm wrong?

+5
source share
2 answers

Your example gives the impression that you have type information that you never had. You wrote:

 Map map = new HashMap (); Set <Map.Entry> set = map.entrySet(); for (Map.Entry entry : set) {} // fine for (Map.Entry entry : map.entrySet()) {} // compilation error 

But map.entrySet() returns a Set , not a Set <Map.Entry> . You have completed an unchecked task that "adds" type information.

In the second loop, we don’t know what is inside Set , so we cannot Set <Map.Entry> over Set <Map.Entry> without an explicit cast.

For example, compare the original example with this, where we do not add type information with unchecked assignment.

 Map map = new HashMap(); Set set = map.entrySet(); for (Map.Entry entry : set) { } // Object cannot be cast to Entry for (Map.Entry entry : map.entrySet()) { } // Object cannot be cast to Entry 

In this case, both cycle loops create a compilation error.

This behavior is described in the Java Language Specification, Section 4.8:

The type of constructor (§8.8), the instance method (§8.8, clause 9.4) or the non-static field (§8.3) M of the raw type C that is not inherited from its superclasses or superinterfaces is the erasure of its type into the general declaration corresponding to C. Type The static member of the raw type C is the same as its type in the general declaration corresponding to C.

+7
source

I think the short answer is that Java allows for "uncontrolled selection" in some situations, but not in others. Working with raw types (generic types without a specified type) is one of these instances.

Keep in mind that for (Map.Entry entry : set) equivalent to:

 Iterator it = set.iterator(); while (it.hasNext()) { Map.Entry entry = it.next(); } 

Appointment:

 Set set = map.entrySet(); 

it is allowed and will not generate any warnings, since you are not introducing any new type, but in the for it.next() loop it will return the Object type and you will get a compiler exception if you assigned it without an explicit cast.

Appointment:

 Set <Map.Entry> set = map.entrySet(); 

allowed, but it will generate an “unchecked throw” warning due to the explicit type Map.Entry and in the for it.next() loop will return the type Map.Entry , and the destination will work fine.

You can put an explicit conversion into a for loop as follows:

 for(Map.Entry entry : (Set<Map.Entry>) map.entrySet()) 
+4
source

All Articles