Java泛型和类型擦除

时间:2010-02-10 02:56:29

标签: java generics type-erasure

给出以下代码:

public void example(Object o) {
  if(o instanceof List<MyType>)
    //do something
}

我理解这是不可能的(以及为什么它不可能)给出Java处理泛型和类型擦除的方式。

我的问题是,实现这一目标的最佳/最干净的方法是什么?或者我唯一能做的就是检查o是否为List<?>

5 个答案:

答案 0 :(得分:2)

您无法检查o instanceof List<?>以上的内容。

从Java泛型中获得的类型安全性仅在编译时发生。 像你这样的方法(它接受一个Object,然后试图找出要做的事情),并不能很好地适应这种设计。 我可以看到为什么这种动态方法有时是必要的,但考虑用类型参数的版本补充它:

public void example(Object o) {
  if(o instanceof List<?>)
     example((List)o);    // can only hope that the type is correct here
}

public void example(List<MyType> list){
    // do something
}

在可以使用它们的情况下,您可以获得泛型的全部好处。在其他情况下,你必须依赖于阅读你的Javadoc的人,并且只传递正确的类型。

即使上述方法无法做到,List<TypeA>List<TypeB>也有两种不同的代码路径。如果您真的需要这样做,请考虑使用自己的包装类型ListOfTypeAListOfTypeB

根据您的需要,甚至可能不需要查看整个列表的擦除类型,只需处理各个元素的运行时类型:

 for (Object o: list){
    if (o instanceof TypeA){
    }
    if (o instanceof TypeB){
    }
 }

答案 1 :(得分:0)

如果没有检查List中所有项的类型,就无法确定Java中泛型参数的类型,因为这只在编译时存在,并在运行之前被删除。

我的建议是,除非你绝对需要让方法接受一个Object(例如符合接口规范或重写Object.equals)以获取你想要的正确类型作为方法的参数并重载您可能需要使用各种其他类型的方法来运行该方法。

答案 2 :(得分:0)

Java在编译后删除了泛型的类型信息,因此您无法动态地以这种方式检查类型参数。

如果此代码的所有路径都限制了type参数,那么执行:

// Return true if object is a list of MyType, false if it is not a list, or is 
// empty
boolean isListOfMyType(Object o) {
    if (o instanceof List) {
        List<?> l = (List<?) o;
        return (l.size() > 0 && (l.get(0) instanceof MyType) 
    }
    return true;
}

是类型安全的,但只有在列表不为空时才会起作用。如果不是,您将需要修改上述内容以检查所有项是否都通过了testof实例(如果您在列表中允许空值,则它们是否为null)。

另一种方法是创建一个扩展说ArrayList<MyType>并使用的子类 这是您的instanceof支票。

最后但并非最不重要的是,拥有一个实现List<MyType>的子类将允许您使用Class.getGenericInterfaces()方法获取type参数。有关详细信息,请参阅this

要使这两种方法中的任何一种工作,您必须确保列表的创建始终实例化其中一种类型。 IE浏览器。如果调用者去构建他们自己的ArrayList<MyType>它将无效。

答案 3 :(得分:0)

与广泛接受的内容相反,可以避免很少知道的类型擦除,这意味着被叫方确实能够知道在呼叫期间使用了哪些通用参数。

请看看: Using TypeTokens to retrieve generic parameters

由于

答案 4 :(得分:-3)

也许通过在运行时检查对象类型,可能是:

if (o.getClass() == List.class) ...

显然,你必须深入挖掘对象的类类型,看它是否与List<>和列表的元素类型完全匹配。