167 votes

casting explicite d'une super-classe vers une sous-classe

public class Animal {
    public void eat() {}
}

public class Dog extends Animal {
    public void eat() {}

    public void main(String[] args) {
        Animal animal = new Animal();
        Dog dog = (Dog) animal;
    }
}

L'affectation Dog dog = (Dog) animal; ne génère pas d'erreur de compilation, mais au moment de l'exécution, il génère une erreur de type ClassCastException . Pourquoi le compilateur ne détecte-t-il pas cette erreur ?

55 votes

VOUS demandez au compilateur de NE PAS détecter l'erreur.

345voto

berry120 Points 21945

En utilisant un cast, vous dites au compilateur : "Faites-moi confiance. Je suis un professionnel, je sais ce que je fais et je sais que, même si vous ne pouvez pas le garantir, je vous dis que ceci animal La variable sera certainement un chien".

Puisque l'animal n'est pas un chien (c'est un animal, on peut faire Animal animal = new Dog(); et ce serait un chien) la VM lance une exception au moment de l'exécution parce que vous avez violé cette confiance (vous avez dit au compilateur que tout irait bien et ce n'est pas le cas !)

Le compilateur est un peu plus intelligent qu'il ne l'est lorsqu'il accepte tout aveuglément, si vous essayez d'intégrer des objets dans des hiérarchies d'héritage différentes (par exemple, intégrer un chien dans une chaîne de caractères), le compilateur vous le renverra parce qu'il sait que cela ne peut pas fonctionner.

Comme il s'agit essentiellement d'empêcher le compilateur de se plaindre, il est important de vérifier à chaque fois que vous ne provoquerez pas d'erreur de type ClassCastException en utilisant instanceof dans une instruction if (ou quelque chose dans ce sens).

0 votes

Merci mais vous devez étendre le chien à partir de l'animal, sinon cela ne fonctionnera pas :)

4 votes

@delive Bien sûr, mais pour répondre à la question, Dog fait s'étendent de Animal ¡!

55voto

Bozho Points 273663

Parce que théoriquement Animal animal puede être un chien :

Animal animal = new Dog();

En règle générale, le downcasting n'est pas une bonne idée. Il faut l'éviter. Si vous l'utilisez, vous avez intérêt à inclure un contrôle :

if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
}

0 votes

Mais le code suivant génère une erreur de compilation Dog dog=new Animal() ; (incompatible types) .mais dans cette situation le compilateur identifie Animal comme une super classe et Dog comme une sous classe.donc l'assignation est erronée.mais quand on cast Dog dog = (Dog) animal ; il accepte .merci de m'expliquer cela

3 votes

Oui, car Animal est une superclasse. Tous les animaux ne sont pas des chiens, n'est-ce pas ? Les classes ne peuvent être désignées que par leur type ou leur supertype. Pas par leurs sous-types.

48voto

Caumons Points 1702

Afin d'éviter ce type d'exception ClassCast, si vous avez :

class A
class B extends A

Vous pouvez définir un constructeur dans B qui prend un objet de A. De cette façon, nous pouvons faire le "cast", par exemple :

public B(A a) {
    super(a.arg1, a.arg2); //arg1 and arg2 must be, at least, protected in class A
    // If B class has more attributes, then you would initilize them here
}

26voto

Zeeshan Points 821

Élaboration de la réponse donnée par Michael Berry.

Dog d = (Dog)Animal; //Compiles but fails at runtime

Vous dites ici au compilateur : "Faites-moi confiance. Je sais que d se réfère en réalité à un Dog objet", alors que ce n'est pas le cas. Rappelez-vous que le compilateur est obligé de nous faire confiance lorsque nous faisons un downcast .

Le compilateur ne connaît que le type de référence déclaré. La JVM, au moment de l'exécution, sait ce qu'est réellement l'objet.

Ainsi, lorsque la JVM s'aperçoit, au moment de l'exécution, que l'élément Dog d se réfère en fait à un Animal et non un Dog o Hey... tu as menti au compilateur et tu as lancé un bon gros ClassCastException .

Par conséquent, si vous êtes en train de faire un downcasting, vous devez utiliser instanceof pour éviter les erreurs.

if (animal instanceof Dog) { Dog dog = (Dog) animal; }

Une question nous vient à l'esprit. Pourquoi diable le compilateur autorise-t-il le downcast alors qu'il va finalement lancer un java.lang.ClassCastException ?

La réponse est que tout ce que le compilateur peut faire, c'est vérifier que les deux types se trouvent dans le même arbre d'héritage. avant le downcast, il est possible que le type animal est du type dog .

Le compilateur doit autoriser des choses qui pourraient fonctionner au moment de l'exécution.

Considérons l'extrait de code suivant :

public static void main(String[] args) 
{   
    Dog d = getMeAnAnimal();// ERROR: Type mismatch: cannot convert Animal to Dog
    Dog d = (Dog)getMeAnAnimal(); // Downcast works fine. No ClassCastException :)
    d.eat();

}

private static Animal getMeAnAnimal()
{
    Animal animal = new Dog();
    return animal;
}

Cependant, si le compilateur est sûr que le cast ne fonctionnera pas, la compilation échouera. Par exemple, si vous essayez d'intégrer des objets dans des hiérarchies d'héritage différentes

String s = (String)d; // ERROR : cannot cast for Dog to String

Contrairement au downcasting, l'upcasting fonctionne de manière implicite, car lorsque vous upcaster, vous limitez implicitement le nombre de métadonnées. contrairement au downcasting, qui implique que plus tard, vous pourriez vouloir invoquer une méthode plus spécifique.

Dog d = new Dog(); Animal animal1 = d; // Works fine with no explicit cast Animal animal2 = (Animal) d; // Works fine with n explicit cast

Les deux cas de figure ci-dessus fonctionneront sans aucune exception car un chien est un animal, et tout ce qu'un animal peut faire, un chien peut le faire. Mais la réciproque n'est pas vraie.

7voto

Sasha Goldshtein Points 2169

Vous demandez au compilateur d'ignorer explicitement son intuition à propos de cette affectation et d'essayer d'effectuer la conversion de toute façon en utilisant l'attribut (Dog) l'expression de la fonte. Et vous vous étonnez d'obtenir une exception au moment de l'exécution ? :-)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X