Downcasting en Java


Upcasting está permitido en Java, sin embargo downcasting da un error de compilación.

El error de compilación se puede eliminar agregando un cast, pero de todos modos se rompería en el tiempo de ejecución.

En este caso, ¿por qué Java permite downcasting si no se puede ejecutar en tiempo de ejecución?
¿Hay algún uso práctico para este concepto?

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");
  }
}
 159
Author: Pshemo, 2008-12-19

9 answers

Se permite el downcasting cuando existe la posibilidad de que tenga éxito en tiempo de ejecución:

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

En algunos casos esto no tendrá éxito:

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

En otros funcionará:

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

Cuando un cast (como este último) falla en tiempo de ejecución,ClassCastException será lanzado.

Tenga en cuenta que algunos casts serán desautorizados en tiempo de compilación, porque nunca tendrán éxito:

Integer i = getSomeInteger();
String s = (String) i; // the compiler will not allow this, since i can never reference a String.
 273
Author: Joachim Sauer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-19 11:17:12

Usando tu ejemplo, podrías hacer:

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();
}
 16
Author: Rolf Rander,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-19 13:08:04

Creo que esto se aplica a todos los lenguajes tipeados estáticamente:

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

El encasillamiento efectivamente dice: asume que esto es una referencia a la clase cast y úsala como tal. Ahora, digamos que o es realmente un Entero, suponiendo que esto es una cadena no tiene sentido y dará resultados inesperados, por lo tanto, debe haber una comprobación de tiempo de ejecución y una excepción para notificar al entorno de tiempo de ejecución que algo está mal.

En la práctica, puede escribir código trabajando en una clase más general, pero lo echó a una subclase, si usted sabe qué subclase es y la necesidad de tratarla como tal. Un ejemplo típico es sobreescribir el objeto.igual(). Supongamos que tenemos una clase para Car:

@Override
boolean equals(Object o) {
    if(!(o instanceof Car)) return false;
    Car other = (Car)o;
    // compare this to other and return
}
 14
Author: Rolf Rander,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-21 23:19:51

Todos podemos ver que el código que proporcionó no funcionará en tiempo de ejecución. Eso es porque sabemos que la expresión new A() puede nunca ser un objeto de tipo B.

Pero el compilador no lo ve así. En el momento en que el compilador está comprobando si el cast está permitido, solo ve esto:

variable_of_type_B = (B)expression_of_type_A;

Y como otros han demostrado, ese tipo de reparto es perfectamente legal. La expresión de la derecha podría muy bien evaluar a un objeto de tipo B. Compilación ve que A y B tienen una relación de subtipos, por lo que con la vista "expresión" del código, el cast podría funcionar.

El compilador no considera el caso especial cuando sabe exactamente qué tipo de objeto expression_of_type_A tendrá realmente. Solo ve el tipo estático como A y considera que el tipo dinámico podría ser A o cualquier descendiente de A, incluyendo B.

 5
Author: Rob Kennedy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-19 15:41:19

En este caso, ¿por qué Java permite downcasting si no se puede ejecutar en tiempo de ejecución?

Creo que esto se debe a que no hay manera de que el compilador sepa en tiempo de compilación si el cast tendrá éxito o no. Para su ejemplo, es simple ver que el molde fallará, pero hay otras veces donde no es tan claro.

Por ejemplo, imagine que todos los tipos B, C y D extienden el tipo A, y luego un método public A getSomeA() devuelve una instancia de B, C o D dependiendo de a número generado aleatoriamente. El compilador no puede saber qué tipo de tiempo de ejecución exacto será devuelto por este método, por lo que si luego envía los resultados a B, no hay forma de saber si la transmisión tendrá éxito (o fallará). Por lo tanto, el compilador tiene que asumir que los casts tendrán éxito.

 2
Author: matt b,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-19 14:17:45

@ Poster original - ver comentarios en línea.

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");
    }
}
 2
Author: Alok Sharma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-27 15:11:01

Downcast funciona en el caso cuando estamos tratando con un objeto upcasted. Upcasting:

int intValue = 10;
Object objValue = (Object) intvalue;

Así que ahora esta variable objValue siempre se puede reducir a int porque el objeto que se lanzó es un Integer,

int oldIntValue = (Integer) objValue;
// can be done 

Pero debido a que objValue es un Objeto, no se puede lanzar a String porque int no se puede lanzar a String.

 1
Author: Uday Reddy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-24 12:05:45

Downcasting es muy útil en el siguiente fragmento de código que uso todo el tiempo. Demostrando así que el downcasting es útil.

private static String printAll(LinkedList c)
{
    Object arr[]=c.toArray();
    String list_string="";
    for(int i=0;i<c.size();i++)
    {
        String mn=(String)arr[i];
        list_string+=(mn);
    }
    return list_string;
}

Almaceno Cadena en la Lista Enlazada. Cuando recupero los elementos de la Lista enlazada, se devuelven los objetos. Para acceder a los elementos como Cadenas(o cualquier otro Objeto de Clase), downcasting me ayuda.

Java nos permite compilar código downcast confiando en que estamos haciendo lo incorrecto. Sin embargo, si los seres humanos cometen un error, se ve atrapado en ejecución.

 0
Author: Drishti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-13 04:57:29

Considere el siguiente ejemplo

public class ClastingDemo {

/**
 * @param args
 */
public static void main(String[] args) {
    AOne obj = new Bone();
    ((Bone) obj).method2();
}
}

class AOne {
public void method1() {
    System.out.println("this is superclass");
}
}


 class Bone extends AOne {

public void method2() {
    System.out.println("this is subclass");
}
}

Aquí creamos el objeto de la subclase Bone y lo asignamos a la superclase AOne reference y ahora la superclase reference no sabe acerca del método method2 en la subclase es decir, Bone durante el tiempo de compilación.por lo tanto, necesitamos rebajar esta referencia de la superclase a la referencia de la subclase para que la referencia resultante pueda conocer la presencia de métodos en la subclase, es decir, Hueso

 0
Author: ZohebSiddiqui,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-08 04:59:04