192 votes

Downcasting en Java

La mise à jour est autorisée en Java, mais la mise à jour entraîne une erreur de compilation.

L'erreur de compilation peut être supprimée en ajoutant une distribution mais de toute façon, elle se briserait à l'exécution.

Dans ce cas, pourquoi Java autorise-t-il le downcasting s'il ne peut pas être exécuté à l'exécution?
Y a-t-il une utilisation pratique pour ce concept?

 public class demo {
  public static void main(String a[]) {
      B b = (B) new A(); // compiles with the cast, 
                         // but runtime exception - java.lang.ClassCastException
  }
}

class A {
  public void draw() {
    System.out.println("1");
  }

  public void draw1() {
    System.out.println("2");
  }
}

class B extends A {
  public void draw() {
    System.out.println("3");
  }
  public void draw2() {
    System.out.println("4");
  }
}
 

315voto

Joachim Sauer Points 133411

Le downcasting est autorisé lorsqu'il est possible qu'il réussisse au moment de l'exécution:

 Object o = getSomeObject(),
String s = (String) o; // this is allowed because o could reference a String
 

Dans certains cas, cela ne réussira pas:

 Object o = new Object();
String s = (String) o; // this will fail at runtime, because o doesn't reference a String
 

Dans d'autres, cela fonctionnera:

 Object o = "a String";
String s = (String) o; // this will work, since o references a String
 

Notez que certains moulages seront interdits au moment de la compilation, car ils ne réussiront jamais du tout:

 Integer i = getSomeInteger();
String s = (String) i; // the compiler will not allow this, since i can never reference a String.
 

18voto

Rolf Rander Points 1764

En utilisant votre exemple, vous pouvez faire:

 public void doit(A a) {
    if(a instanceof B) {
        // needs to cast to B to access draw2 which isn't present in A
        // note that this is probably not a good OO-design, but that would
        // be out-of-scope for this discussion :)
        ((B)a).draw2();
    }
    a.draw();
}
 

16voto

Rolf Rander Points 1764

Je crois que cela s'applique à tous les langages statiquement typés:

String s = "some string";
Object o = s; // ok
String x = o; // gives compile-time error, o is not neccessarily a string
String x = (String)o; // ok compile-time, but might give a runtime exception if o is not infact a String

Le transtypage dit effectivement: supposons que c'est une référence à la fonte de la classe et de l'utiliser comme tel. Maintenant, permet de dire o est vraiment un Entier, en supposant que c'est une Chaîne de caractères n'a pas de sens et qui va donner des résultats inattendus, il faut donc un moment de l'exécution et une exception à notifier à l'environnement d'exécution que quelque chose est faux.

Dans la pratique, vous pouvez écrire du code de travail sur une classe plus générale, mais la convertir en une sous-classe si vous savez ce que sous-classe, il est et devez le traiter comme tel. Un exemple typique est primordial d'Objet.equals(). Supposons que nous disposions d'une classe pour Voiture:

@Override
boolean equals(Object o) {
    if(!(o instanceof Car)) return false;
    Car other = (Car)o;
    // compare this to other and return
}

5voto

Rob Kennedy Points 107381

Nous pouvons tous voir que le code que vous avez fourni ne fonctionne pas au moment de l'exécution. C'est parce que nous savons que l'expression new A() peut jamais être un objet de type B.

Mais ce n'est pas la façon dont le compilateur voit. Au moment où le compilateur est de vérifier si la distribution est autorisée, il voit juste ceci:

variable_of_type_B = (B)expression_of_type_A;

Et comme d'autres l'ont démontré, ce genre de casting est parfaitement légal. L'expression sur le droit pourrait très bien correspondre à un objet de type B. Le compilateur voit qu' A et B ont un sous-type de rapport, donc, avec le "expression" vue du code, le casting pourrait fonctionner.

Le compilateur ne pas envisager le cas particulier quand il sait exactement quel type d'objet expression_of_type_A aurez vraiment. Il voit juste le type statique comme A et estime que le type dynamique pourrait être A , ou tout descendant d' A, y compris l' B.

2voto

Alok Sharma Points 1

@ Affiche originale - voir les commentaires en ligne.

 public class demo 
{
    public static void main(String a[]) 
    {
        B b = (B) new A(); // compiles with the cast, but runtime exception - java.lang.ClassCastException 
        //- A subclass variable cannot hold a reference to a superclass  variable. so, the above statement will not work.

        //For downcast, what you need is a superclass ref containing a subclass object.
        A superClassRef = new B();//just for the sake of illustration
        B subClassRef = (B)superClassRef; // Valid downcast. 
    }
}

class A 
{
    public void draw() 
    {
        System.out.println("1");
    }

    public void draw1() 
    {
        System.out.println("2");
    }
}

class B extends A 
{
    public void draw() 
    {
        System.out.println("3");
    }

    public void draw2() 
    {
        System.out.println("4");
    }
}
 

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