2008-12-30 17 views
5

Hullo alle,"Dynamic" Casting in Java

Sie fragen, ob es irgendwelche Java Hacker sind, die können Ahnung mich in auf, warum die folgende nicht funktioniert:

public class Parent { 
    public Parent copy() { 
     Parent aCopy = new Parent(); 
     ... 
     return aCopy; 
    } 
} 

public class ChildN extends Parent { 
    ... 
} 

public class Driver { 
    public static void main(String[] args) { 
     ChildN orig = new ChildN(); 
     ... 
     ChildN copy = orig.getClass().cast(orig.copy()); 
    } 
} 

Der Code recht glücklich ist zu kompilieren, aber entscheidet, eine ClassCastException zur Laufzeit zu werfen D =

Edit: Whoah, wirklich schnelle Antworten. Danke Leute! Es scheint also, dass ich mit dieser Methode nicht downcast. Gibt es eine andere Möglichkeit, Downcasting in Java durchzuführen? Ich habe darüber nachgedacht, jede ChildN Klasse copy() zu überschreiben, war aber nicht begeistert von dem Hinzufügen des zusätzlichen Standardcodes.

+0

Sie können es tun. Sieh dir meinen Schnitt an. Ich hatte Probleme, das "Casting" an erster Stelle zu verstehen. – OscarRyz

Antwort

1

(Code kann nicht in einen Kommentar eingefügt werden, daher füge ich hier hinzu)

In Bezug auf Cloneable: Wenn Sie Clonable implementieren, implementieren Sie es wie folgt; viel sauberer zu nennen ...

public class Foo implements Cloneable { 
    public Foo clone() { 
     try { 
      return (Foo) super.clone(); 
     } catch (CloneNotSupportedException e) { 
      return null; // can never happen! 
    } 
} 

[EDIT:. Ich habe auch andere Leute verwenden

throw new AssertionError("This should never happen! I'm Cloneable!"); 

im catch-Block gesehen]

+0

In der Tat, so habe ich es gemacht! Obwohl mein Kommentar eher in Richtung // JAVA EPIC FAIL :) – user50264

6

Die Besetzung effektiv versucht, dies zu tun:

ChildN copy = (ChildN) orig.copy(); 

(Es funktioniert die Besetzung aus zur Ausführungszeit durchzuführen, aber das ist, was es sein wird, weil orig.getClass()ChildN.class sein wird) jedoch orig.copy() nicht Wenn Sie eine Instanz von ChildN zurückgeben, wird nur eine Instanz von Parent zurückgegeben, sodass sie nicht in ChildN umgewandelt werden kann.

4

Wenn ChildN nicht copy() außer Kraft setzt eine Instanz von ChildN zurück, dann versuchen Sie, ein Objekt vom Typ Eltern niedergeschlagenen ChildN

9

ist wie der Versuch, dies zu geben zu tun:

public Object copy(){ 
     return new Object(); 
    } 

und dann Versuch:

String s = (String) copy(); 

Ihre Eltern Klasse und ChildN Klasse haben die gleiche Beziehung wie Objekt und String

Um es Ihnen folgendes tun müssten funktioniert:

public class ChildN extends Parent { 
    public Parent copy() { 
     return new ChildN(); 
    } 
} 

Das heißt, überschreiben die „Kopie“ Methode und das Rück das Recht Beispiel.


EDIT

Wie pro Ihre bearbeiten. Das ist tatsächlich möglich. Dies könnte eine Möglichkeit sein:

public class Parent { 
    public Parent copy() { 
     Parent copy = this.getClass().newInstance(); 
     //... 
     return copy; 
    } 
} 

Auf diese Weise müssen Sie die „Kopie“ -Methode in jeder Unterklasse nicht außer Kraft setzen. Dies ist das Prototyp-Entwurfsmuster.

Bei der Verwendung dieser Implementierung sollten Sie jedoch auf zwei geprüfte Ausnahmen achten. Hier ist das komplette Programm, das kompiliert und ohne Probleme läuft.

+0

Mit gutem Beispiel lehren! Diese Antwort ist mir sehr klar. Kann Child.copy auch deklariert werden, um eine ChildN iso a Parent zurückzugeben? (Ich weiß in C++ kann es) – xtofl

+0

Nicht in Java. Zumindest nicht im Java-Quellcode. Um das Problem ein wenig zu verwirren, ist es * in Java-Byte-Code erlaubt ... –

+1

Es ist im Quellcode in Java 5+ erlaubt. –

2

java.lang.Class # cast (Object) löst eine ClassCastException aus, wenn die Klasse # isInstance() false zurückgibt.Von der javadoc für diese Methode:

Bestimmt, ob das angegebene Object zuweisungskompatibel mit dem Objekt ist von dieser Klasse vertreten. Diese Methode ist die dynamische Äquivalent der Java Sprache Instanceof Operator ... Insbesondere wenn diese Class Objekt eine deklarierten Klasse darstellt, gibt diese Methode true wenn die angegebene Object Argument eine Instanz der Klasse ist, dargestellt (oder einer seiner Unterklassen); es gibt sonst false zurück.

Da Elternteil keine Unterklasse von Kind ist, isinstance() false zurückgibt, so werfen() wirft die Ausnahme. Dies kann das Prinzip der geringsten Verwunderung verletzen, aber es funktioniert so, wie es dokumentiert ist - cast() kann nur upcast, nicht downcast.

2

Könnte es sein, dass Sie einfach eine Kopie/Klon Ihres Objekts wollen.

In diesem Fall implementieren Sie die Cloneable-Schnittstelle und überschreiben clone() nach Bedarf.

Dies tut genau das, was Ihre "copy()" -Methode auf Java versucht.

(Ja, Sie zu extravagant Selbstbeobachtung Spiele tun könnten, aber diese Methoden versagen oder so bald hässlich werden, wie Sie keinen öffentlichen Standard-Konstruktor haben. Clont egal in jedem Fall funktioniert, was Konstruktoren Sie haben.)

+0

Funktioniert auch! Ich habe gehört, dass clone() einen schlechten Ruf hat, aber nicht genau über die genauen Gründe. – user50264

+0

Dies könnte der "andere" mögliche Weg sein. Es besteht keine Notwendigkeit, die Methodensignatur (mit clone und return Object) zu kopieren, da name und Parent as return tun sollten. – OscarRyz

0

Der Grund Downcasting funktioniert nicht, weil, Wenn Sie ein übergeordnetes Objekt in einen untergeordneten Typ umwandeln, können Sie die Methoden des untergeordneten Typs für das übergeordnete Objekt nicht aufrufen. Aber es funktioniert andersrum ...