如何确定参数在泛型中是否是正确的类型

时间:2011-08-11 00:28:14

标签: java generics casting map error-handling

我正在使用以下必需的方法签名编写地图实现。

我需要确保价值是正确的类型。我认为如果两种类型不相等,这种检查会导致异常,但事实并非如此。无论如何要检查这个吗?

public boolean containsValue(Object value) {

    try {
        V temp = (V) value;
    } catch (Exception e) {
        throw new ClassCastException("Value is not of correct type");
    }
    ...

3 个答案:

答案 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是正确的答案。

至于你的问题,由于类型擦除,没有办法看到传递的对象是否与泛型类型相同。

相关问题