在Java中使用通配符和在抽象方法中声明泛型类型之间的区别

pum*_*sha 7 java generics inheritance abstract

我试图理解Java中的泛型类型,理论上它看起来是可以理解的,但是当我需要将它应用于实际代码时,我遇到了问题.我想声明将返回泛型类型的抽象方法.让我们假设我有一个名为Magicable的空接口,2类实现它:Magican和Witch.现在我想知道这3个声明之间的区别是什么:

/*1*/protected abstract <T extends Magicable> List<T> getMagicables();
/*2*/protected abstract List<? extends Magicable> getMagicables();
/*3*/protected abstract List<Magicable> getMagicables();
Run Code Online (Sandbox Code Playgroud)
  1. 在第一种情况下,当我想在扩展抽象类的某个类中实现此方法的主体时,我遇到了问题:

    @Override
    protected List<Magican> getMagicable() {..}
    
    Run Code Online (Sandbox Code Playgroud)

    我有警告信息:

    类型安全:MagicanService类型的getMagicable()的返回类型List <Magican>需要未经检查的转换以符合MagicableService类型的List <Magicable>.

  2. 在第二种情况下,我没有这个警告,但我在抽象类中有问题,我在上面声明了抽象方法:

      public void <T extends Magicable> T getOneFromList() {
          List<T> list = getMagicables();
          //.....
      }
    
    Run Code Online (Sandbox Code Playgroud)

    在这种情况下,我在getMagicables()调用中有编译错误:

    类型不匹配:无法从List <capture#2-of转换?将Magicable>扩展到List <T>

  3. 第三种情况导致上述两个代码中的编译错误.在我的情况下,我不认为它是否正确解决.

Max*_*Max 2

  1. 第一个案例

只需声明你的方法:

    @Override
    protected <T extends Magicable> List<T> getMagicables() {
       List<T> list = ...
       return list
    }
Run Code Online (Sandbox Code Playgroud)

如果你真的想要这个:

    @Override
    protected List<Magican> getMagicable() {..}
Run Code Online (Sandbox Code Playgroud)

您可能必须在类定义中声明您的通用 T

     public abstract class AbstractKlass<T extends Magicable> {
        protected abstract List<T> getMagicables();
     }
Run Code Online (Sandbox Code Playgroud)

然后在你的子类中:

     public class MySubClass extends AbstractKlass<Magican> {

        @Override
        protected List<Magican> getMagicables() {
           ...
        }
     }
Run Code Online (Sandbox Code Playgroud)
  1. 第二种情况

编译错误是正常的,因为<? extends Magicable>从方法的签名来看,从您可以将这些元素视为 Magicable 的那一刻起,您就不再关心列表中的内容了。打电话时

    List<T> list = getMagicables();
Run Code Online (Sandbox Code Playgroud)

你想在不知情的情况下照顾T型。换句话说,有 3 个用例:T 是 Magicable(OK)、T 是 Magician(错误,因为 getMagicables 可能返回 Witch 列表)和 T 是 Witch(也是错误)。

  1. 为什么我使用? extends Magicable而不是仅仅Magicable在列表中

因为List<Magician>是 的子类型,List<? extends Magicable>但不是 的子类型List<Magicable>。这对于方法的参数很有用。

    public void doIt(List<? extends Magicable> list) {
         // you can't add a Magician here
    }
Run Code Online (Sandbox Code Playgroud)

可以用作

    List<Witch> list = ...
    doIt(list);
Run Code Online (Sandbox Code Playgroud)

但如果你有

    public void doIt(List<Magicable> list) {
         // you can add a Magician here
    }
Run Code Online (Sandbox Code Playgroud)

你不能用它作为

    List<Witch> list = ...
    doIt(list); // compile error
Run Code Online (Sandbox Code Playgroud)