16

我正在扩展一个库中定义的类,我无法更改:

public class Parent
{
    public void init(Map properties) { ... }
}

如果我正在定义一个扩展 Parent 的类 'Child' 并且我使用 Java 6 和泛型,那么在不收到未经检查的警告的情况下覆盖 init 方法的最佳方法是什么?

public class Child extends Parent
{
    // warning: Map is a raw type. References to generic type Map<K,V> should be parameterized
    public void init(Map properties) { }
}

如果我添加泛型参数,我会得到:

   // error: The method init(Map<Object,Object>) of type Child has the same erasure as init(Map) of type Parent but does not override it
   public void init(Map<Object,Object>) { ... }
   // same error
   public void init(Map<? extends Object,? extends Object>) { ... }
   // same error
   public void init(Map<?,?>) { ... }

无论我使用特定类型、有界通配符还是无界通配符,都会出现此错误。是否有正确或惯用的方法来覆盖非泛型方法而不发出警告,并且不使用 @SuppressWarnings("unchecked")?

4

4 回答 4

13

是的,您必须使用与父类中相同的签名声明覆盖方法,而无需添加任何泛型信息。

我认为你最好的选择是将@SuppressWarnings("unchecked")注释添加到原始类型参数,而不是方法,这样你就不会压制你自己的代码中可能有的其他泛型警告。

于 2008-10-28T01:09:43.867 回答
3

简短的回答:没有办法做到这一点。

不满意的答案:禁用 IDE/build.xml 中的(特定)警告。

如果你不能改变库,唉,你必须坚持使用非泛型方法。

问题是,尽管在类型擦除之后,两个 init() 都具有相同的签名,但它们实际上可能是不同的方法——或者相同的 (*)。编译器无法判断它应该覆盖还是重载,所以它是被禁止的。

(*) 假设库开发者的意思是 init(Map<String,Integer>)。现在您正在实现 init(Map<String,String>)。这是重载,在 Child 类的 vtable 中应该存在两个方法。

但是如果库开发者的意思是 init(Map<String,String>) 呢?然后它是覆盖的,并且您的方法应该替换Child类中的原始init,并且Child的vtable中只有一个方法。

PS 我讨厌泛型是如何在 Java 中实现的 :-(

于 2008-10-28T01:05:22.937 回答
2

我认为上面的答案是说 @SuppressWarnings("rawtypes") 。

于 2011-04-28T17:33:14.540 回答
0

您必须声明与父方法具有相同签名的方法,因此编译时会收到警告。您可以使用 @SuppressWarnings("unchecked") 压制它们

无法摆脱这种情况的原因是,警告的存在是为了让您知道可以创建其中包含无效类型的集合。只有当所有可能允许的代码都被删除时,警告才会消失。由于您是从非泛型类继承的,因此始终可以创建包含无效内容的 Collection。

于 2008-10-28T17:57:41.960 回答