5

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

不能更新的超类:

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;
    }
}
4

5 回答 5

12

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

如果您能够更新超类:

TestSuper中,您将使用 usepublic List<? extends Animal> addAnimals()而不是public List<Animal> 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);
于 2013-10-09T15:08:25.433 回答
2

如果Dog是 的子类Animal,您可能会这样做

以下签名:

public List<? extends Animal> addAnimals()

然后做

public List<Dog> addAnimals()

在子类中。

或者你可以使超类通用<T>和实现类<Dog>

于 2013-10-09T15:11:47.507 回答
2

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

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

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


同样在被覆盖的方法中,您不能将列表的泛型类型更改为具有该泛型类型的超类型的列表(例如List<Dog>to List<Animal>)。为什么?让我们看一下这个例子

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

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


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

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

class Sub extends Super<Dog> {

    @Override
    public List<Dog> addAnimals() {
        return null;
    }
}
于 2013-10-09T15:13:19.690 回答
0

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

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

以下代码必须有效:

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

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

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

于 2013-10-09T15:35:17.910 回答
0

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

TestSuper<T extends Animal> {

  public List<T> addAnimals() {

  }
}

TestSub extends TestSuper<Dog> {


}
于 2013-10-09T15:10:28.927 回答