【问题标题】:How to override generic list return type in java如何在java中覆盖泛型列表返回类型
【发布时间】:2013-10-17 00:47:35
【问题描述】:

我正在尝试覆盖在子类中返回类型为列表的方法,如下例所示,由于泛型问题,我无法在我的子类中执行此操作。我无法更改我的超类代码,那么我该如何解决这个问题?任何人都可以请指导我...非常感谢提前。

不能更新的超类:

public class Animal {
           private String legs;
    }

public class TestSuper {

    public List<Animal> addAnimals() {
        return animals;
    }
}

子类:

public class Dog extends Animal {
         private String sound;
    }

public class TestSub extends TestSuper {

    public List<Dog> addAnimals() { --> I need to override this method but want return type as List of dogs
        return null;
    }
}

【问题讨论】:

  • 你只能用赋值兼容的类型覆盖返回类型。但是,泛型不是协变的。 List&lt;Dog&gt; 不是 List&lt;Animal&gt; 的子类型。见this thread

标签: java generics


【解决方案1】:

如果超类真的不能更新,恐怕你根本就不能更新。

如果您能够更新超类:

TestSuper 中,您应该使用public List&lt;? extends Animal&gt; addAnimals() 而不是public List&lt;Animal&gt; addAnimals()

您还有哪些其他解决方案:

你可以使用这样的实用方法:

@SuppressWarnings("unchecked")
public static <T extends Animal> List<T> cast(List<Animal> animals, Class<T> subclass) {
    List<T> out = new ArrayList<T>();
    for (Animal animal : animals) {
        if (!subclass.isAssignableFrom(animal.getClass())) {
            // the "animal" entry isn't an instance of "subclass"
            // manage this case however you want ;)
        } else {
            out.add((T) animal);
        }
    }
    return out;
}

然后,调用:

List<Dog> dogs = TheClassNameYouChose.cast(animals, Dog.class);

【讨论】:

  • 感谢您的回复,但我的项目中确实有该选项,因此期待建议:(
  • 想要使用超类中的 addAnimals()...因此我试图覆盖
  • @Satya 是的,我明白了,这个想法很好,但是如果你不能更改TestSuper#addAnimals() 方法的签名,那根本不可能......
【解决方案2】:

您需要让 TestSuper 使用泛型才能真正使其正常工作。

TestSuper<T extends Animal> {

  public List<T> addAnimals() {

  }
}

TestSub extends TestSuper<Dog> {


}

【讨论】:

    【解决方案3】:

    如果DogAnimal 的子类,你可以这样做

    以下签名:

    public List<? extends Animal> addAnimals()
    

    那就做吧

    public List<Dog> addAnimals()
    

    在子类中。

    或者你可以让超类泛型&lt;T&gt;和实现类&lt;Dog&gt;

    【讨论】:

      【解决方案4】:

      您不能将 List 的泛型类型更改为该泛型类型的子类型。问题是对任何实例的引用都可以是该实例的子类型。那么让我们看看这个例子

      SuperType sup = new SubType();
      sup.getAnimals().add(new Cat());
      //adding cat is possible because getAnimals() returns List<Animal>
      

      所以你应该将Cat 添加到应该只包含Dogs 的列表中,这是错误的。


      此外,在覆盖方法中,您不能将列表的泛型类型更改为具有该泛型类型的超类型的列表(例如 List&lt;Dog&gt;List&lt;Animal&gt;)。为什么?让我们看看这个例子

      SuperType sup = new SubType();
      Dog d = sup.getAnimals().get(0);
      

      在子类型中,我们有动物列表,因此get(0) 可能会返回猫。


      如果您可以更改类中的代码,请尝试这种方法

      class Super<T extends Animal> {
          public List<T> addAnimals() {
              return null;
          }
      }
      
      class Sub extends Super<Dog> {
      
          @Override
          public List<Dog> addAnimals() {
              return null;
          }
      }
      

      【讨论】:

        【解决方案5】:

        这是不可能的。超类合同说,如果你有:

        class Animal {}
        class Dog extends Animal {}
        class Cat extends Animal {}
        

        以下代码必须有效:

        TestSuper test = new AnySubclassOfTestSuper(); // including TestSub!
        test.addAnimals().add(new Cat());
        

        您在TestSub 类中的覆盖会违反这一点,因为您不能将Cat 添加到List&lt;Dog&gt;。由于这违反了面向对象类型系统的一个相当基本的原则,因此您不会找到解决此限制的完美解决方法。

        将超类更改为使用List&lt;? extends Animal&gt; 的建议会起作用,因为您无法向该列表添加任何内容。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-04-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-05-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多