我正在使用以下必需的方法签名编写地图实现。
我需要确保价值是正确的类型。我认为如果两种类型不相等,这种检查会导致异常,但事实并非如此。无论如何要检查这个吗?
public boolean containsValue(Object value) {
try {
V temp = (V) value;
} catch (Exception e) {
throw new ClassCastException("Value is not of correct type");
}
...
答案 0 :(得分:4)
由于类型擦除,您无法使用标准instanceof
运算符。规范方法是将类本身或其实例传递到某处。
然后您可以使用反射来检查实例类型:
private Class<V> clazz; // somehow this gets set
public boolean containsValue(Object value){
if(clazz.isInstance(value)){
// safe:
V temp = (V) value;
}
您还可以使用Class.isAssignableFrom
检查继承树:
if(clazz.isAssignableFrom(value.getClass())){
// safe:
V temp = (V) value;
}
请注意,这可以保证这是一种类型安全的转换,但不要求类型相同,例如V
可以是Number
,但value
可以是Integer
类型。
至于获取clazz
,您可以在构造函数中强制执行它:
public class MyMap<K,V>{
private final Class<V> clazz;
public MyMap(Class<V> clazz){
this.clazz = clazz;
}
...
这个类的初始化程序可能类似于:
MyMap<Integer,String> foo = new MyMap<Integer,String>(String.class);
我一般都赞成在构造函数中传递类型,并将字段标记为final
,因为语义和限制会阻止您更改该字段,这是合理的,因为实例通常依赖于编译时保证,假设类型参数不变。
答案 1 :(得分:1)
为什么你需要V型的值? Map接口的定义方式并非偶然。
您应该接受作为Object的值,然后调用value.equals(someOtherValueInYourMap)。
例如:
public boolean containsValue(Object value) {
V v1 = ...;
V v2 = ...;
V v3 = ...;
return value.equals(v1) || value.equals(v2) || value.equals(v3);
}
假设地图v1,v2,v3中有三个值。 v1,v2,v3和参数值的类型无关紧要,因为equals方法在Object中定义,您可以随时调用它来比较对象。如果value实际上是一个不能与V实例进行比较的不同类型,那么它的equals方法将抛出一个ClassCastException,除非你捕获它,否则它将进一步传播。别担心。
答案 2 :(得分:0)
它不抛出异常的原因是因为地图不能包含不同类型的对象,所以false是正确的答案。
至于你的问题,由于类型擦除,没有办法看到传递的对象是否与泛型类型相同。