使用原始类型参数重写方法时,是否可以避免未选中的警告?

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

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”)?


答案 1

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

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


答案 2

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

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

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

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

(*)假设库开发人员指的是 init(Map<String,Integer>)。现在你正在实现 init(Map<String,String>)。这是重载,子类的 vtable 中应存在两个方法。

但是,如果库开发人员指的是 init(Map<String,String>)呢?然后它是重写的,你的方法应该替换 Child 类中的原始 init,并且在 Child 的 vtable 中只有一个方法。

附言:我讨厌泛型在Java中实现的方式:-(


推荐