简体   繁体   English

为什么Java不抱怨通用地图转换?

[英]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. Q1。 Why Java allows such casting at run-time? 为什么Java允许在运行时进行这样的转换?

Q2. Q2。 If using bean, what is the best practice to avoid this error? 如果使用bean,避免此错误的最佳做法是什么?

Q1. Q1。 Because at run-time, all generic info is already stripped away, so the two Map types are indistinguishable for the run-time environment. 因为在运行时,所有generic信息都已被删除,因此两种Map类型在运行时环境中无法区分。 The generics are only there to help the compiler enforce type safety. generics只是帮助编译器强制类型安全。 To quote the Java Tutorials : 引用Java教程

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. 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 ). 我认为它不会因为类型擦除而在runtyme中抱怨( http://docs.oracle.com/javase/tutorial/java/generics/erasure.html )。 In runtime there is no difference between this declarations of map. 在运行时,这个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> . 问题是编译的字节码由于类型擦除问题没有任何通用信息 (这是为了确保向后兼容性)所以,就JVM而言, HashMap<anything,anything>扩展Map<anythingelse,anythingelse>

As to question 2: you were getting a warning. 至于问题2: 得到一个警告。 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. 如果从Spring上下文中获取Map实例,则无法保持类型安全性。 The Spring BeanFactory is a runtime container and doesn't have a clue as to what the generic type params of an instance are. Spring BeanFactory是一个运行时容器,并没有关于实例的泛型类型params的线索。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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