覆盖泛型返回类型的方法

时间:2011-02-28 16:48:58

标签: java generics

假设我有一个定义以下抽象方法的超类

public abstract <T extends Interface> Class<T> getMainClass();

现在,如果我想在某个子类中重写它

public Class<Implementation> getMainClass(){
    return Implementation.class;
}

我收到有关类型安全和未选中转换的警告:

  

类型安全:类型Class<Implementation>getMainClass()的返回类型SubFoo需要未经检查的转换,以符合类型Class<Interface> SuperFoo >

如果Class<Implementation>Class<T>不属于<T extends Interface>?有没有办法正确摆脱警告?

4 个答案:

答案 0 :(得分:12)

重写方法的返回类型必须是重写方法的返回类型的子类型。

Class<Impl>不是Class<T>的子类型<T extends Interface>。 T在这里不得而知。

Class<Impl>是每个子类型规则Class<? extends Interface>的子类型。


关于通配符的一些子类型规则:

适用于任何类型X

  • A<X>A<? extends X>

  • 的子类型
  • A<X>A<? super X>

  • 的子类型

如果ST

的子类型
  • A<? extends S>A<? extends T>

  • 的子类型
  • A<? super T>A<? super S>

  • 的子类型

更简洁,(<:表示“是”)的子类型

A<S>    <:    A<? extends S>    <:    A<? extends T>

A<T>    <:    A<?  super  T>    <:    A<?  super  S>

答案 1 :(得分:3)

请考虑以下类似于您的方案:

public class SuperFoo {
     public abstract <T extends Interface> List<T> getList();
} 

public class SubFoo extends SuperFoo {
     private List<Implementation> l = new ArrayList<Implementation>();

     public List<Implementation> getList() {
          return l;
     }

     public void iterate() {
          for (Implementation i: l) ...;
     }
}

SubFoo subFoo = new SubFoo();
SuperFoo superFoo = subFoo;
superFoo.getList().add(new AnotherImplementation()); // Valid operation!
subFoo.iterate(); // Unexpected ClassCastException!

在这种情况下,未经检查的转化警告会警告您出现意外ClassCastException的可能性。

但是,在您的情况下,当返回类型为Class<...>时,这不是问题(据我所知),因此您可以合法地禁止警告:

@SuppressWarnings("unchecked")
public Class<Implementation> getMainClass(){ ... }  

另一个选择是让SuperFoo本身通用:

public class SuperFoo<T extends Interface> {
    public abstract Class<T> getMainClass(); 
}

public class SubFoo extends SuperFoo<Implementation> {
    public Class<Implementation> getMainClass() { ... }
}

对于另一个(也许是最好的)选项,请参阅Stas Kurilin的回答。

答案 2 :(得分:1)

试试这个

public abstract Class<? extends Interface> getMainClass();

重组示例 通过这样的警告java试图阻止像这样的案件

class OtherImpl implements Interface{ 
} 
A a = new B();//where A - your abstract class and B - implementation
Class<OtherImpl> other = a.<OtherImpl>getMainClass();//some broken think, But _without_ runtime exception

正如@axtavt提到的例子被打破了。我重组了它。

答案 3 :(得分:0)

为什么你想要public abstract Class<? extends Interface> getMainClass();而不是public abstract Interface getMainClass();

我认为您只需返回Interface的实例,然后,如果调用者想要访问底层运行时类,只需在返回的对象上调用getClass()即可。

基本上,我认为你可以做到

public InterfaceImpl implements Interface {
    // ...
};

public abstract class A {
    public abstract Interface getMainClass();
    // ...
}

public class AImpl {
    return new InterfaceImpl();
}

public class Main {
    public static void main(String[] args) {
        AImpl aImpl = new AImpl();
        Interface i = aImpl.getMainClass();
        System.out.println(i.getClass());
    }
}