type specific castear cast java casting

specific - Downcasting en Java



dynamic casting java (9)

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

El error de compilación se puede eliminar agregando un molde, 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 el 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"); } }


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

Creo que esto se debe a que no hay forma de que el compilador sepa en tiempo de compilación si el reparto tendrá éxito o no. Para su ejemplo, es simple ver que el elenco fallará, pero hay otros momentos en los que no está tan claro.

Por ejemplo, imagina 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 un 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 transfiere los resultados a B , no hay manera de saber si el reparto tendrá éxito (o fallará). Por lo tanto, el compilador debe asumir que los moldes tendrán éxito.


@ Póster original: consulta los 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"); } }


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 referencia de superclase AOne y ahora la referencia de superclase no conoce el método method2 en la subclase, es decir, Bone durante el tiempo de compilación. Por lo tanto, tenemos que bajar esta referencia de superclase a referencia de subclase para que la referencia resultante puede conocer la presencia de métodos en la subclase, es decir, Hueso


Creo que esto se aplica a todos los idiomas tipificados de forma estática:

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 dice con eficacia: supongamos que se trata de una referencia a la clase de cast y utilícela como tal. Ahora, supongamos que o es realmente un Entero, suponiendo que se trata de una Cadena no tiene sentido y dará resultados inesperados, por lo que debe haber una comprobación de tiempo de ejecución y una excepción para notificar al entorno de ejecución que algo anda mal.

En el uso práctico, puede escribir código que trabaje en una clase más general, pero lo puede convertir a una subclase si sabe qué subclase es y necesita tratarlo como tal. Un ejemplo típico es anular Object.equals (). Supongamos que tenemos una clase para el automóvil:

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


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

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

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

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

pero como objValue es un Objeto, no se puede convertir a String porque int no se puede convertir a String .


Downcasting es muy útil en el siguiente fragmento de código. Uso esto todo el tiempo. Demostrando así que 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; }

Guardo cadena en la lista vinculada. 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. Aún así, si los humanos cometemos un error, se detecta en tiempo de ejecución.


Downcasting está permitido cuando existe la posibilidad de que suceda en el 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

Tenga en cuenta que algunos lanzamientos no se permitirán en el momento de la 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.


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() nunca puede ser un objeto de tipo B

Pero así no es como lo ve el compilador. Para cuando el compilador comprueba si el molde está permitido, simplemente ve esto:

variable_of_type_B = (B)expression_of_type_A;

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

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


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