2016-11-16 3 views
1

Ich arbeite mit einer API in meiner Firma, wo ich eine Unterklasse für ein vorhandenes Objekt erstellen möchte. Hier sind die Einsprüche:So werfen Sie ein Objekt in Java

  • ich nicht den übergeordneten Klasse
  • ändern kann ich nicht ändern kann, wie das Super Objekt instanziiert wird

Das Beispiel sehe ich am häufigsten einen Hund als Unterklasse von Tiere ist, so Ich werde das benutzen. Sagen wir, Sie in der API dieser Klasse haben:

//API class, which I cannot modify 
public class Animal(){ 
    public void eat(){ 
     //All animals can do this 
    } 
} 

Nun würde Ich mag eine Klasse wie folgt zu schaffen, die ein paar Methoden zu Tierhinzufügt.

//My subclass, which I can modify 
public class Dog extends Animal(){ 
    public void fetch(){ 
     //Only dogs can do this 
    } 
} 

So, jetzt lassen Sie uns sagen, ich habe eine Instanz von Animal (eine, die nicht ein Hund ist). Ich muss es im Grunde in einen Hund niederschlagen. Ich habe gehört, dass Downcasting nicht direkt in Java unterstützt wird, aber gibt es einen Workaround dafür?

public class AnimalExample{ 
    public static void main(String[] args){ 
     Animal animal = MyApi.getAnAnimal(); 
     //Dog dog = (Dog) animal; ---throws a runtime error 
     Dog dog = Dog.getDog(animal); //Maybe something like this? 

     //Then I should be able to call both eat() and fetch() 
     dog.eat(); 
     dog.fetch(); 
    } 
} 

Noch einmal, ich verstehe, dass Downcasting nicht direkt unterstützt wird. Aber es muss ein Workaround dafür geben, und ich kann es nicht herausfinden. Ich weiß, dass ich eine Wrapper-Klasse verwenden könnte (zB DogWrapper), aber das wäre etwas schwieriger, als ich es gerne hätte, weil ich immer noch die Dutzende von Superklassen-Methoden anrufe.

UPDATE: Ich verstehe, dass es noch kein Hund ist, aber ich fragte mich, ob es einen Weg gab, es in einen Hund umzuwandeln. Es klingt im Grunde nach dem, was die Leute sagen, dass ich es entweder manuell konvertieren muss (kopiere jedes Attribut/jede Methode einzeln) oder verwende einfach eine Wrapper-Klasse. Ein Wrapper-Kurs scheint viel weniger chaotisch zu sein, also muss ich leider diesen Weg gehen. So wird DogWrapper eine fetch() Methode und eine getAnimal() Methode haben. Also wenn ich die Dog essen möchte, dann muss ich dog.getAnimal().eat() anrufen. Ich habe es vermieden, das zu tun, aber ich denke, es gibt keinen Weg. Sieht jemand etwas einfacher als das?

+2

„Ich brauche es im Wesentlichen in einen Hund zu niedergeschlagenen“ Aber es ist * nicht * a 'dog'. Du kannst nicht einen Nicht-Hund bitten, sich wie ein 'Hund' zu verhalten. Downcasting * wird * unterstützt, aber es ist sicher ausgeführt ... die Umwandlung ist nur erfolgreich, wenn der Ausführungszeittyp mit dem angeforderten Typ kompatibel ist. Was würden Sie von 'dog.fetch()' erwarten? Was passiert, wenn es einige in 'Dog' deklarierte Felder verwendet, die nicht im eigentlichen Objekt sind? –

+0

Also, du hast ein 'Tier', das kein' Hund' ist, aber du willst es trotzdem behandeln, als wäre es ein 'Hund'. Sie müssen es selbst in einen 'Hund' umwandeln; Java kann nicht selbst wissen, wie das geht. (Und warum glaubst du, dass das nützlich ist? Wenn das Tier kein 'Hund' ist, was sollte es dann tun, wenn du eine Methode namens" Hund "nennen würdest?). – Jesper

+0

Ich würde vorschlagen, etwas zu tun wie if (Tier instanceof Dog) {Hund dog = (Hund) Tier} else {// handle problem case} – mdewit

Antwort

0

Sie können einen Konstruktor haben, der Animal übernimmt und den Dog-Teil des Objekts mit Standardwerten oder nach Bedarf instanziiert.

public Dog (Animal animal) { 
    super(); // any instantiation that has to be done for animal 
    // Dog instantiation 
    // Use animal properties as required 
} 
Dog dog = new Dog(animal); 

mit auch eine statische Methode, wie Sie erwähnt Dog.getDog(animal) eine Option ist, hängt von Ihrer Codierung bevorzugt.

+0

Das Problem dabei ist, dass ich das _original_ 'Animal' Objekt nicht mehr benutze. Die Instanz von "Hund" ist ein brandneues "Tier". Wenn ich also 'dog.eat()' aufrufen würde, würde es die 'essen() 'Methode für das' Tier' nennen, das in 'super()' erstellt wurde, nicht das ursprüngliche 'Tier', das zuerst erstellt wurde. –

+0

@JakeFairbairn was Sie sagen, ist nicht wahr, das einzige, was Sie mit dem ursprünglichen Tierobjekt tun, ist kopieren Sie alle Eigenschaften, die Sie benötigen, machen Sie eine tiefe Kopie, so dass keine Referenzen aus dem ursprünglichen Objekt verwendet werden. Dies führt dazu, dass ein brandneues Dog-Objekt instanziiert wird, und wenn du dog.eat anrufst, wird es auf dem neuen Objekt sein. – tinker

0

Angenommen, ich erstelle eine Methode, die eine Dog erfordert, soll aber die Animal API erweitern. Sicher, ich könnte nur die Unterschrift wie so machen:

public void doFetch(Dog dog) 

Aber wie gesagt, ich will die Animal API erweitern. Nun, wenn die angegebene Animal keine Dog ist, kann ich nicht abrufen. In diesem Sinne kann ich folgendes tun:

public void doFetch(Animal fetcher) { 
    if(fetcher instanceof Dog) { 
     Dog dog = (Dog) fetcher; 
     ... //Do fetchy things 
     return; 
    } 
    //If we reach this point, then the animal is not a dog 
    throw new IllegalArgumentException("fetcher is not a Dog!"); 
} 

Nun nehmen wir an, wie in Ihrem Fall, ich habe eine Animal, die kein Hund ist, aber ich will es ein Dog aus irgendeinem Grund sein. In diesem Fall könnte ich alle Animal in einen Hund mit einer Art von Übersetzer konvertieren.Ich ziehe es Dinge wie diese als static Methoden in der Dog Klasse selbst zu definieren:

//Breaks the laws of nature by making a Dog from any Animal. 
public static Dog fromAnimal(Animal animal) { 
    Dog dog = new Dog(); 
    //Here you would set all the properties of the animal, e.g.: 
    dog.setName(animal.getName()); 
    ... 
    return dog; 
} 
+0

Ja, ich dachte über eine Kopie des 'Tier' in einem neuen 'Hund'-Objekt nach, aber das ist wirklich chaotisch . Wenn Änderungen in "Animal" vorgenommen werden, werden sie nicht in "Dog" angezeigt. Außerdem gibt es fast hundert Setter, die ich durchfahren muss, was schon hässlich ist. –