代码之家  ›  专栏  ›  技术社区  ›  sk.

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

  •  14
  • sk.  · 技术社区  · 16 年前

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

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

    如果我定义了一个扩展父级的类“子”,并且我用泛型使用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 回复  |  直到 14 年前
        1
  •  12
  •   Dov Wasserman    16 年前

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

    我想你最好的办法是加上 @SuppressWarnings("unchecked") 注释到原始类型参数,而不是方法,因此您不会压制您自己的代码中可能存在的其他泛型警告。

        2
  •  2
  •   Vladimir Dyuzhev    16 年前

    简短的回答:没有办法。

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

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

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

    (*) 假设库开发人员的意思是init(map<string,integer>)。现在您正在实现init(map<string,string>)。这是重载,子类的vtable中应该存在两个方法。

    但是,如果库开发人员的意思是init(map<string,string>)?然后它将被重写,您的方法应该 代替 子类中的原始init,子类的vtable中只有一个方法。

    P.S.我讨厌泛型如何在Java中实现:

        3
  •  2
  •   Zemian    14 年前

    我认为上面的答案是说@suppresswarnings(“rawtypes”)。

        4
  •  0
  •   DJClayworth    16 年前

    您必须使用与父级相同的签名声明该方法,因此在编译时将收到警告。您可以使用@suppresswarnings(“unchecked”)抑制它们。

    无法消除此问题的原因是,存在警告以告知您可以创建包含无效类型的集合。只有当所有允许删除的代码都被删除时,警告才会消失。由于您是从非泛型类继承的,因此始终可以创建包含无效内容的集合。