2013-04-14 6 views
6

Hallo, ich frage mich, ob es eine einfache Lösung für mein Problem ist,Arraylist verschiedene Objekte derselben Superklasse enthält - wie Methode einer Unterklasse zugreifen

Ich habe eine 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()); 

Sie alle implementieren eine Methode move() - Die Bird fliegt, wenn move() aufgerufen wird. Ich weiß, ich gemeinsame Methoden und Eigenschaften der Super-Klasse unter Verwendung dieser

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

ist das in Ordnung zugreifen können - aber jetzt würde Ich mag die move() Methode für den Zugriff auf die Unterklasse Bird hat. Ich kann dies durch Gießen der Animal als Bird:

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

In meiner Situation mag ich nicht, dies zu tun, wie es Ich habe 3 verschiedene Sätze des obigen Codes eines für jeden Subtyp bedeuten Animal.

Es scheint ein bisschen überflüssig, gibt es einen besseren Weg?

+3

Warum sollte nicht Tier hat eine 'move()' Methode, die Sie in den Unterklassen außer Kraft setzen? –

+0

... Call move? Wenn es die Unterklassen-Implementierung nicht aufruft, gibt es etwas, was Sie uns nicht sagen. –

+1

@ user2278797 Nur damit Sie es wissen: Ich habe Ihre Frage zur besseren Formatierung bearbeitet und die Namen der Klassen geändert (weil sie in Ihrem Code inkonsistent waren): Ich entfernte die 's'-e aus den Namen in den Zeilen, zu denen sie hinzugefügt wurden 'Tierliste'. Sie waren: 'animalList.add (new Reptiles()); Tierliste.füge hinzu (neue Vögel()); animalList.add (new Amphibians()); 'Und jetzt sind:' animalList.add (new Reptile()); animalList.add (neuer Vogel()); animalList.add (neuer Amphibian()); '. Wenn Sie sie in einem beliebigen Code verwendet haben, stellen Sie sicher, dass Sie sie entsprechend ändern oder den Code Ihrer Frage erneut bearbeiten. – acdcjunior

Antwort

12

Es gibt wirklich keine schöne Möglichkeit, dies von der Oberklasse aus zu tun, da das Verhalten jeder Unterklasse anders sein wird. Um sicherzustellen, dass Sie tatsächlich die entsprechende move-Methode aufrufen, ändern Sie Animal von einer Oberklasse in eine Schnittstelle. Wenn Sie dann die Methode move aufrufen, können Sie sicherstellen, dass Sie für das gewünschte Objekt die entsprechende move-Methode aufrufen.

Wenn Sie nach allgemeinen Feldern suchen, können Sie eine abstrakte Klasse AnimalBase definieren und alle Tiere benötigen, um davon aufzubauen, aber jede Implementierung muss die Animal Schnittstelle implementieren.

Beispiel:

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(); 
} 
+0

Okay, aber was ist mit all den üblichen Methoden und Verhaltensweisen, die zwischen den Unterklassen geteilt werden. Wäre es nicht überflüssig, dieselben Methoden und Eigenschaften zu deklarieren, die dieselben Dinge in jeder einzelnen Unterklasse tun und beschreiben? Zum Beispiel habe ich einige gemeinsame Eigenschaften Name, Geschlecht, Farbe usw. und dann einige Methoden wie essen und schlafen. Danke für Ihre schnellen Antworten übrigens. – whiteElephant

+0

An diesem Punkt * könnte * Sie ein abstraktes Objekt namens 'AnimalBase' haben, das die benötigten Felder zur Verfügung stellt. Sie möchten dann davon ausgehen und die Schnittstelle "Tier" implementieren. – Makoto

+0

Danke Makoto, kann ich fragen, ob es eine korrektere Art gibt, dieses Problem zu lösen? z.B. Ist es besser, eine abstrakte Basisklasse zu verwenden und die anderen Methoden zu implementieren, oder wäre es besser, bestimmte Methoden leer zu lassen und sie für jede Unterklasse zu überschreiben? Prost – whiteElephant

0

In Ihrem Fall könnte die folgende Arbeit, aber die Zeit Komplexität ist O (n):

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

Ich nehme an, dass jedes Tier eine move() -Methode hat. – BlackJoker

1

Sie brauchen nicht jedes Casting zu tun. Die überschriebene Methode sollte [simple Polymorphismus] gecallt

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

Above Code sollte Vogel-Methode aufrufen, wenn das Objekt von Vogel ist, ist es nicht?

Und Casting ist keine Lösung, wie entscheiden Sie, welches Objekt zu werfen? Sie müssen instanceOf verwenden.

+0

Danke, könnte eine mögliche Lösung sein. Ich bin mir nicht sicher, ob ich verstehe, was du meinst. Und Casting ist keine Lösung. Wie entscheidest du, welches Objekt du werfen willst? Sie müssen instanceOf "verwenden, der Benutzer würde auf ein Objekt klicken, also ein Tier, und das würde die Indexnummer von wo für wo es in der ArrayList platziert werden .. Cheers – whiteElephant

+0

So machst du das: animalList.add (new Reptil()); animalList.add (new Bird()); animalList.add (new Amphibian()); Jetzt beim Abrufen von Objekten entweder müssen Sie verfolgen, welches Objekt an welchem ​​Ort ist, um richtiges Casting oder Sie zu tun Ich benötige instanceof Operator, um zu überprüfen, ob du am Ende vielleicht Amphibian zu Bird machst. Du hast meinen Punkt? – Lokesh

+0

Ok ich denke schon - wenn ich das stattdessen gemacht habe – whiteElephant

-1
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(); 
+2

Was machst du damit überhaupt *? Alles, was ich tun wollte, war 'move' bei jeder Art von' Animal' zu nennen. Warum konzentrierst du dich so sehr auf 'Bird'? – Makoto

+0

Ja, es gibt keinen Fokus auf Vogel - es wurde nur als Beispiel benutzt. – whiteElephant