ArrayList, содержащий различные объекты одного и того же суперкласса - как получить доступ к методу подкласса

Привет мне интересно, есть ли простое решение моей проблемы,

у меня есть ArrayList:

ArrayList <Animal> animalList = new ArrayList<Animal>(); 

/* I add some objects from subclasses of Animal */

animalList.add(new Reptile());
animalList.add(new Bird());
animalList.add(new Amphibian());

они все реализуют метод move() - в Bird мухи, когда move() называется. Я знаю, что могу получить доступ к общим методам и свойствам супер класса, используя это

public void feed(Integer animalIndex) {
    Animal aAnimal = (Animal) this.animalList.get(animalIndex);
    aAnimal.eat();
}

это нормально - но теперь я хотел бы получить доступ к move() метод подкласса Bird есть. Я мог бы сделать это, бросив Animal как Bird:

Bird aBird = (Bird) this.animalList.get(animalIndex);
aBird.move();

в моей ситуации я не хочу этого делать, так как это будет означать, что у меня есть 3 разных набора вышеуказанного кода по одному для каждого подтипа Animal.

это кажется немного избыточным, есть ли лучший способ?

4 ответов


на самом деле нет хорошего способа сделать это из суперкласса, так как поведение каждого подкласса будет различным.

чтобы убедиться, что вы на самом деле вызова соответствующего move способ, изменить Animal от суперкласса до интерфейса. Тогда, когда вы называете move метод, вы сможете убедиться, что вы вызываете соответствующий метод перемещения для объекта, который вы хотите.

если вы хотите сохранить общие поля, то можно определить абстрактный класс AnimalBase, и требуют, чтобы все животные строили из этого, но каждая реализация должна будет реализовать Animal интерфейс.

пример:

public abstract class AnimalBase {
    private String name;
    private int age;
    private boolean gender;

    // getters and setters for the above are good to have here
}

public interface Animal {
    public void move();
    public void eat();
    public void sleep();
}

// The below won't compile because the contract for the interface changed.
// You'll have to implement eat and sleep for each object.

public class Reptiles extends AnimalBase implements Animal {
    public void move() {
        System.out.println("Slither!");
    }
}

public class Birds extends AnimalBase implements Animal {
    public void move() {
        System.out.println("Flap flap!");
    }
}

public class Amphibians extends AnimalBase implements Animal {
    public void move() {
        System.out.println("Some sort of moving sound...");
    }
}

// in some method, you'll be calling the below

List<Animal> animalList = new ArrayList<>();

animalList.add(new Reptiles());
animalList.add(new Amphibians());
animalList.add(new Birds());

// call your method without fear of it being generic

for(Animal a : animalList) {
    a.move();
}

вам не нужно делать любой формы. Переопределенный метод должен называться [простой полиморфизм]

Animal aAnimal==  this.animalList.get(animalIndex);
aAnimal.move();

выше код должен вызывать метод bird, если объект имеет bird, не так ли?

и литье не является решением, как вы решите, какой объект бросить? Вам придется использовать instanceOf.


в вашем случае может работать следующее, но сложность времени O (n):

public void moveBird(){
    for(Animal aminal:animalList){
        if(animal instanceof Bird){
            aninmal.move();
        }
    }
}

Bird getMyBird(Integer aniInteger) {
        Bird b = new Bird();
        //Do somthig with bird object...

        return b;
        //get your modifeid bird object
    }

    Bird myBird = animalList.get(animalIndex);

    myBird.move();