简体   繁体   中英

Why doesn't Java complain about generic map casting?

Object stringMap = new HashMap<String, String>(){{ put("1", "a"); }};
Map<Integer, String> integerMap = (Map<Integer, String>)stringMap; // Why doesn't Java throw an exception at run-time?

// I know this is not a problem if stringMap is declared as Map<String, String>.
// However, the actual code above was using Spring Bean.
// Map<Integer, String> integerMap = (Map<Integer, String>)context.getBean("map");

System.out.println(integerMap.get(1)); // prints null
System.out.println(integerMap.get("1")); // prints a

Q1. Why Java allows such casting at run-time?

Q2. If using bean, what is the best practice to avoid this error?

Q1. Because at run-time, all generic info is already stripped away, so the two Map types are indistinguishable for the run-time environment. The generics are only there to help the compiler enforce type safety. To quote the Java Tutorials :

Generics are implemented by type erasure: generic type information is present only at compile time, after which it is erased by the compiler. The main advantage of this approach is that it provides total interoperability between generic code and legacy code that uses non-parameterized types (which are technically known as raw types). The main disadvantages are that parameter type information is not available at run time, and that automatically generated casts may fail when interoperating with ill-behaved legacy code.

Q2. Don't use raw-typed Maps. If you have to, be really really careful when you typecast them.

I think it doesn't complains in runtyme because of type erasure ( http://docs.oracle.com/javase/tutorial/java/generics/erasure.html ). In runtime there is no difference between this declarations of map.

You are getting a compiler warning on an unchecked cast. The trouble is the compiled bytecode doesn't have any generic information because of type erasure problem (which is there to ensure backwards compatibility) so, as far as the JVM is concerned, a HashMap<anything,anything> extends Map<anythingelse,anythingelse> .

As to question 2: you were getting a warning. Don't ignore them! ;)

If you are fetching a Map instance from the Spring context, then there will be no way for you to maintain type safety. The Spring BeanFactory is a runtime container and doesn't have a clue as to what the generic type params of an instance are.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM