2008-12-30 8 views
5

Ohé tous,« dynamique » Avec en Java

Vous vous demandez s'il y a des pirates Java qui peut me la moindre idée de la raison pour laquelle à ce qui suit ne fonctionne pas:

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

Le code est très heureux pour compiler, mais décide de lancer une ClassCastException à l'exécution D =

Editer: Whoah, des réponses vraiment rapides. Merci les gars! Donc, il semble que je ne peux pas downcast en utilisant cette méthode ... est-il un autre moyen de faire de downcasting en Java? J'ai pensé que chaque classe ChildN écraserait copy(), mais n'était pas enthousiaste à l'idée d'ajouter le code supplémentaire.

+0

Vous pouvez le faire. Jetez un oeil à mon édition. Je pensais que vous aviez des problèmes à comprendre "couler" en premier lieu. – OscarRyz

Répondre

1

(Impossible d'ajouter du code dans un commentaire, donc je vais ajouter ici)

En ce qui concerne Cloneable: si vous implémentez Cloneable, implémentez-le comme suit; beaucoup plus propre à appeler ...

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

[EDIT:. Je l'ai aussi vu d'autres personnes utilisent

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

dans le bloc catch]

+0

En effet, c'est ainsi que j'ai fini par le faire! Bien que mon commentaire était plus sur les lignes de // JAVA EPIC FAIL :) – user50264

6

Le casting tente effectivement de le faire:

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

(Il travaille le casting pour effectuer au moment de l'exécution, mais c'est ce que ce sera parce que orig.getClass() sera ChildN.class), orig.copy() ne porte toutefois pas renvoie une instance de ChildN, elle renvoie une instance de Parent, elle ne peut donc pas être convertie en ChildN.

4

Si ChildN ne remplace pas la copie() pour retourner une instance de ChildN, alors vous essayez de downcaster un objet de parent de type à l'ChildN

9

est comme essayer de le faire:

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

et puis tenter de:

String s = (String) copy(); 

Votre classe Parent et ChildN classe ont la même relation que objet et Chaîne

Pour le faire fonctionner, vous devrez effectuer les opérations suivantes:

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

C'est, remplacer la méthode « copie » et retourner le droit exemple.


EDIT

Selon votre édition. C'est réellement possible. Cela pourrait être un moyen possible:

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

De cette façon, vous ne devez pas remplacer la méthode « copie » dans chaque sous-classe. C'est le modèle de conception de prototype. Toutefois, en utilisant cette implémentation, vous devez être conscient de deux exceptions vérifiées. Voici le programme complet qui compile et s'exécute sans problèmes.

public class Parent { 
    public Parent copy() throws InstantiationException, IllegalAccessException { 
     Parent copy = this.getClass().newInstance(); 
     //... 
     return copy; 
    } 
} 
class ChildN extends Parent {} 

class Driver { 
    public static void main(String[] args) throws InstantiationException , IllegalAccessException { 
     ChildN orig = new ChildN(); 
     ChildN copy = orig.getClass().cast(orig.copy()); 
     System.out.println("Greetings from : " + copy); 
    } 
} 
+0

Enseigner par l'exemple! Cette réponse est très claire pour moi. Est-ce que Child.copy peut également être déclaré pour renvoyer un ChildN iso a Parent? (Je sais en C++ ça peut) – xtofl

+0

Pas en Java. Au moins pas dans le code source Java. Pour confondre légèrement le problème, il est * autorisé * dans le code octet Java ... –

+1

Il est autorisé dans le code source dans Java 5+. –

2

java.lang.Class # cast (Object) jette un ClassCastException si classe # isInstance() retourne false.De la javadoc pour cette méthode:

Détermine si l'objet spécifié est compatible pour l'affectation avec l'objet représenté par cette classe. Cette méthode est l'équivalent dynamique de l'opérateur instanceof langage Java ... Plus précisément, si ce objet Class représente une classe déclarée, cette méthode renvoie true si spécifié l'argument Object est une instance de la classe représentée (ou de l'une quelconque de ses sous-classes); il renvoie false sinon.

Puisque Parent n'est pas une sous-classe de child, isInstance() renvoie false alors cast() lève l'exception. Cela peut aller à l'encontre du principe du moindre étonnement, mais il fonctionne de la façon dont il est documenté - cast() ne peut être que grisé, pas baissé.

2

Se pourrait-il que vous vouliez simplement une copie/clone de votre objet.

Dans ce cas, implémentez l'interface Cloneable et remplacez clone() si nécessaire.

public class Parent implement Cloneable { 
    public Object clone() throws CloneNotSupportedException { 
    Parent aCopy = (Parent) super.clone(); 
    ... 
    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.clone()); 
    } 
} 

Ceci fait exactement ce que votre méthode "copy()" a essayé de faire de la manière Java.

(Oui, vous pouvez faire des jeux de fantaisie d'introspection aussi, mais ces méthodes échouent ou deviennent laids dès que vous ne disposez pas d'un défaut constructeur public. Clone fonctionne dans tous les cas, peu importe ce que les constructeurs que vous avez.)

+0

Fonctionne aussi! J'ai entendu dire que clone() a une mauvaise réputation, mais pas sûr des raisons exactes. – user50264

+0

Cela pourrait être "l'autre" possible. Il n'est pas nécessaire de changer la signature de la méthode (en utilisant clone et return Object) copy comme nom et Parent comme return devrait le faire. – OscarRyz

0

La raison pour laquelle le travail ne marche pas downcasting est parce que, Lorsque vous copiez un objet parent sur un type enfant, il est impossible d'invoquer les méthodes du type enfant sur l'objet parent. Mais ça marche dans l'autre sens ...