[英]Generics in HashMap implementation
在Java实现中,我发现
transient Entry[] table;
which is initiated in constructor as
table = new Entry[capacity];
我知道并了解不允许创建通用数组,但是我无法理解的是整个过程是如何工作的。 我的意思是当我们做类似的事情时
HashMap<Integer, String> hMap = new HashMap<Integer, String>();
上面的代码如何导致创建类型为<Integer, String>
的Entry数组
好吧,很少有人无法理解我的要求。 改写我要问的是做这样的事情有什么意义
HashMap<Integer, String> hMap = new HashMap<Integer, String>();
当它不导致
Entry<Integer, String>
泛型是编译时的安全性。 在运行时,地图仅了解对象。 这称为类型擦除 。 为了进一步吓到您,以下代码将毫无问题地运行:
Map<Integer, Integer> safeMap = new HashMap<>();
Map unsafeMap = safeMap;
unsafeMap.put("hello", "world");
您将在编译时收到警告,因为您使用的是原始Map而不是通用Map,但在运行时根本不执行任何检查,因为该Map是可以存储任何对象的良好旧Map。 只有编译器才能阻止您在映射或整数中添加字符串。
该实现使类型为Entry<K,V>
对象数组
static class Entry<K,V> implements Map.Entry<K,V>
而不提供通用类型参数( source )。 这是允许的,但要理解编译器不再保证类型安全。 例如,在代码的其他地方,您可以编写
Entry<K,V> e = table[bucketIndex];
编译器将允许您执行此操作。 如果您确定始终将table[]
元素设置为null
或Entry<K,V>
,则可以知道分配是正确的。
这样做没有问题的原因是Java中的泛型类型是通过类型擦除实现的,即Entry<K,V>
对象Entry<Integer,Integer>
和Entry<String,Long>
在运行时没有区别。
尝试以这种方式思考Java泛型:类型参数仅适用于引用类型的表达式的静态类型,不适用于在运行时引用值所引用的实际实例的类型 。
在阅读Java代码时,我发现了开发正确直觉的上述关键。 所以下次你看到
new HashMap<Integer, String>()
读如下:“这是类型为HashMap<Integer, String>
的实例创建表达式。在运行时,该表达式将产生对HashMap
类实例的引用。” 只要编译器可以精确地跟踪您对该表达式结果的处理方式,它就可以保持知道确实是HashMap<Integer, String>
,但是HashMap<Integer, String>
。
现在,由于静态类型系统的功能不足以跟踪数组的组件类型上的类型参数(Java的数组类型是协变量的事实在这里发挥了重要作用),因此代码被迫脱离静态类型安全网络。 关键的观察是,这本身并不会使代码不正确 ,而只会限制编译器发现编程错误的能力。 这就是为什么Java允许您从原始类型到泛型类型进行未经检查的强制转换,尽管并非没有警告,这标志着您已经离开了静态类型安全的省份。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.