看看这个短班。
它做什么?它是一个HashMap,其中键是一个Class对象,值是一个Hashmap,其键和值由Class对象定义。
假设你想要一个方法add(K obj),这将是一个方便的方法。你为什么要强迫用户输入add(Person.class,personInstance),当你也可以让他只是传递实例本身时 - 代码应该能够获取对象的类并将实例放在键下面对象的类。但我不能。 add(K obj)便捷方法无法编译:
public class TypedHashmap extends HashMap<Class, HashMap> {
public <K> HashMap<K, K> getHashMap(Class<K> type) {
return (HashMap<K, K>) getOrDefault(type, new HashMap<K, K>());
}
public <K> void add(K obj, Class<K> type) {
HashMap<K, K> toModify = getHashMap(type);
toModify.put(obj, obj);
}
public <K> void add(K obj) {
add(obj, obj.getClass());
}
}
编译错误:
我可以看到Java不确定obj.getClass()类型。但我不明白为什么。是因为它不能确保该类实际上不是扩展K的东西吗?这里有什么问题?这可以以某种方式解决吗?
答案 0 :(得分:3)
泛型是确保类型安全的工具。
您设计API的方式是不类型对此级别安全,这就是您收到此错误的原因。
public <K> void add(K obj) {
add(obj, (Class<K>) obj.getClass());
}
是否明确表示您无法确保此处的类型安全。或者只是做一个
public void add(Object obj) {
add(obj, (Class<Object>) obj.getClass());
}
这将为您提供相同级别的类型安全(无)。
如果你想要一个稍微清洁的解决方案(在简单的添加功能中没有强制转换),你也必须修改你的其他添加功能。
public <K> void add(K obj, Class<? super K> type) {
HashMap<K, K> toModify = getHashMap(type);
toModify.put(obj, obj);
}
public void add(Object obj) {
add(obj, obj.getClass());
}
但最后我相信你正在实施反模式。
问题在于:
Number a = new Integer(3);
map.add(a);
map.getHashMap(Number.class).contains(a);
产生错误。 Number
地图中的整数不。因为您的地图不支持子类型和继承。
将Integer
对象添加到列表中。但除非我知道哪个
答案 1 :(得分:1)
就编译器而言obj.getClass()
返回类型为Class<?>
的实例,并且您没有带签名的方法
void add(K obj, Class<?> type)
你有
void add(K obj, Class<K> type)
虽然很接近,但并不完全正确。
答案 2 :(得分:1)
您没有使您的类具有通用性,因此所有方法泛型都是独立的(每个K
都是不同的ANY)。我想你想要像
public class TypedHashmap<K> extends HashMap<Class<K>, HashMap<K, Class<K>>> {
public HashMap<K, Class<K>> getHashMap(Class<K> type) {
return (HashMap<K, Class<K>>) getOrDefault(type, new HashMap<>());
}
public void add(K obj, Class<K> type) {
HashMap<K, Class<K>> toModify = getHashMap(type);
toModify.put(obj, type);
}
public void add(K obj) {
add(obj, (Class<K>) obj.getClass());
}
}