【问题标题】:How to determine if parameter is correct type in Generics如何确定参数是否是泛型中的正确类型
【发布时间】:2011-08-11 00:28:14
【问题描述】:

我正在编写一个带有以下所需方法签名的地图实现。

我需要确保值的类型正确。我认为如果两种类型不相等,此检查会导致异常,但事实并非如此。有没有办法检查这个?

public boolean containsValue(Object value) {

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

【问题讨论】:

  • 编译器会对该泛型转换发出警告。不要忽视这些警告。
  • 通过要求它是 V 型,您违反了 containsValue() 方法的约定,当 value.equals(v) 的 Map 中存在值 v 时,该方法返回 true(或者如果它们都是空的),不管value的类

标签: java generics casting map error-handling


【解决方案1】:

由于类型擦除,您不能使用标准的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,因为语义和限制会阻止您更改该字段,这是合理的,因为实例通常依赖于假定类型参数不变的编译时保证。

【讨论】:

  • 好吧,我有点明白你在说什么,但我该如何以及在哪里放置 clazz 的东西?
  • @Jeff:它只需要成为您班级中的一个字段。我建议在你的构造函数中设置它的值。
  • 所以,看起来像这样: public class MyMap{ public MyMap(Class clazz){ this.clazz = clazz; } 是它自己独立的构造函数吗?这如何与我已经写过的相结合?
  • @Jeff:你需要修改你当前的构造函数。
【解决方案2】:

为什么需要 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 ,除非您捕获它,否则它将被进一步传播。不用担心。

【讨论】:

  • +1 人总是试图强制对象为值的类型,这与 Map 中方法的规范相矛盾
【解决方案3】:

它不抛出异常的原因是因为映射不能包含不同类型的对象,所以错误是正确的答案。

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

【讨论】:

  • value是传入的外部对象;不是地图中的对象
猜你喜欢
  • 1970-01-01
  • 2022-12-16
  • 2011-06-11
  • 1970-01-01
  • 2011-08-23
  • 1970-01-01
  • 1970-01-01
  • 2020-09-21
  • 1970-01-01
相关资源
最近更新 更多