【发布时间】:2015-11-19 09:28:17
【问题描述】:
提前道歉,我正在为如何措辞问题标题而苦苦挣扎,我知道这并不理想。
所以我尝试实现我自己的 Java HashMap 小版本,当然我希望它适用于泛型,以允许它与任何类一起使用,就像真正的 HashMap 一样。
在我的get(...) 方法中,我传递了一个键并想要返回一个值。一切正常,直到我尝试返回某些东西,然后我收到常见的Xlint:unchecked 类型安全警告,即无法验证我的返回值类型。看下面的sn-p:
public <K, V> V get (K key) {
if(!(key instanceof Object)) {
System.out.println("ERROR: key given can't be guaranteed to have a hash function");
return null;
}
int hashCode = key.hashCode();
int index = hashCode % items.length;
HashItem slot = items[index];
while(slot != null) {
if(slot.getKey().equals(key)) {
V val = slot.getVal();
return val;
}
slot = slot.getNext();
}
return null;
}
参考见.getVal()的定义:
public V getVal() {
return HashItem.this.val;
}
.getVal() 方法是私有内部类HashItem<K, V> 的一部分:
private class HashItem <K, V> {
// blah blah
}
自制的哈希映射类本身的结构如下:
public class MyHash <K, V>
{
// blah blah
private class HashItem <K, V> {
// blah blah
public V getVal() {
return HashItem.this.val;
}
// blah blah
}
public MyHash (int capacity, double newLoadFactor) {
// blah blah
}
// blah blah etc etc
}
由于K 和V 始终保持不变,我不明白为什么不能保证.getVal() 的类型,或者如何解决这个问题。我尝试像这样进行转换:(V) 可以工作,但返回 unchecked cast 错误。我也尝试只返回值,但我只得到返回类型Object,这是不可接受的。
如何让我的.getVal() 方法返回正确的类型?
【问题讨论】:
-
get不应该是通用方法。类应该是通用的,而不是方法,所以public <K, V> V get (K key)中的<K, V>不应该存在。 -
我没有专门看这段代码,但是很多基于集合的类——尤其是那些使用数组的类,就像哈希映射一样——由于类型而存在未经检查的警告异常擦除。警告并不意味着您做错了什么,只是类型系统无法帮助您;您应该确保它是正确的,然后使用
@SuppressWarnings("unchecked")抑制警告。单独说明:Java 中每个类都是 Object 的子类,所以不用勾选instanceof Object。 -
HashItem也不应该有类型参数<K, V>,它应该只使用来自MyHash的参数。 -
另请注意,在真正的
HashMap中,get接受Object,而不是K。起初这似乎是错误的,但这样做真的很重要。如果get和containsKey接受K而不是Object,则无法检查Map<? extends CharSequence, Object>是否包含密钥"Foo",因为您无法将String传递给get或containsKey方法。put,另一方面应该接受K和V。