Question

Bonjour à tous,

Vous vous demandez s'il y a des pirates informatiques Java qui peuvent m'indiquer pourquoi 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 assez heureux pour la compilation, mais décide de lever une exception ClassCastException à l'exécution D =

Modifier: Whoah, des réponses très rapides. Merci les gars! Donc, il semble que je ne puisse pas baisser en utilisant cette méthode ... existe-t-il un autre moyen de le faire en Java? Je pensais que chaque classe ChildN écraserait copy () , mais je n'étais pas enthousiaste à l'idée d'ajouter le code standard supplémentaire.

Était-ce utile?

La solution

(Je ne peux pas ajouter de code dans un commentaire, je vais donc ajouter ici)

À propos de 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: J'ai aussi vu d'autres personnes utiliser

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

dans le bloc des captures.]

Autres conseils

C'est comme essayer de faire ceci:

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

Et essayez ensuite de:

  String s = ( String ) copy();

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

.

Pour que cela fonctionne, vous devez procéder comme suit:

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

Autrement dit, remplacez le " copier " méthode et retourner la bonne instance.


MODIFIER

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

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

De cette manière, vous n’avez pas à remplacer le " copier " méthode dans chaque sous-classe. C'est le modèle de conception du prototype.

Cependant, en utilisant cette implémentation, vous devez connaître deux exceptions vérifiées. Voici le programme complet qui compile et fonctionne 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 );
    }
}

La distribution tente effectivement de le faire:

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

(La distribution doit être exécutée au moment de l'exécution, mais c'est ce qui se passera, car orig.getClass () sera ChildN.class ). Cependant, < code> orig.copy () ne renvoie pas d'instance de ChildN, mais uniquement de parent . Il ne peut donc pas être converti en ChildN .

Si ChildN ne remplace pas copy () pour renvoyer une instance de ChildN, vous tentez de convertir un objet de type parent en ChildN

java.lang.Class # cast (Object) lève une exception ClassCastException si Class # isInstance () renvoie false. Depuis le javadoc pour cette méthode:

  

Détermine si l'objet spécifié est   affectation compatible avec l'objet   représentés par cette classe. Cette méthode   est l'équivalent dynamique du Java   langue instance de l'opérateur ...   Plus précisément, si cela   L'objet Class représente un   classe déclarée, cette méthode retourne    true si le paramètre spécifié    Object est un argument   instance de la classe représentée (ou   de l'une de ses sous-classes); il revient    false sinon.

Puisque Parent n'est pas une sous-classe de l'enfant, isInstance () renvoie false. cast () lève l'exception. Cela peut violer le principe du moindre étonnement, mais il fonctionne de la manière dont il est documenté - cast () ne peut que retransmettre, pas décroître.

Peut-être voulez-vous simplement une copie / un 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());
     }
}

Cela correspond exactement à ce que vous & copy; copy () " méthode essayée de faire à la manière de Java.

(Oui, vous pouvez aussi faire des jeux d’introspection sophistiqués, mais ces méthodes échouent ou deviennent laides dès que vous n’avez pas de constructeur par défaut public. Clone fonctionne dans tous les cas, quels que soient vos constructeurs.)

La raison pour laquelle le downcasting ne fonctionne pas est que, lorsque vous convertissez un objet parent en un type enfant, vous ne pouvez pas invoquer les méthodes du type enfant sur l'objet parent. Mais cela fonctionne dans l'autre sens ...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top