Why am I losing type information?

前端 未结 2 1010
挽巷
挽巷 2021-01-13 07:28

I have found something interesting to happen with Maps, rawtypes and generics. Following code:

static {
          Map map = new HashMap ();
          Set &l         


        
相关标签:
2条回答
  • 2021-01-13 08:03

    I think the short answer is that Java allows "unchecked cast" in some situations but not others. Dealing with raw types (Generic types without a specified type) is one of these instances.

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

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

    The assignment:

    Set set = map.entrySet();
    

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

    The assignment:

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

    is allowed but will generate an "unchecked cast" warning because of the explicit type Map.Entry and in the for loop it.next() will return type Map.Entry and the assignment will work fine.

    You can put the explicit cast in the for loop like this:

    for(Map.Entry entry : (Set<Map.Entry>) map.entrySet())
    
    0 讨论(0)
  • 2021-01-13 08:25

    Your example makes it look like you have type information that you never had. You have written:

    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() is returning Set, not Set <Map.Entry>. You've performed an unchecked assignment which "adds" type information.

    In the second for loop, we don't know what's inside the Set, so we can't iterate over Set <Map.Entry> without an explicit cast.

    For example, compare the original example to this one where we don't "add" type information with the 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 for loops produce a compilation error.

    This behaviour is documented in the Java Language Specification, section 4.8:

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

    0 讨论(0)
提交回复
热议问题