Pregunta ¿Cómo funciona Java Object casting detrás de la escena? [duplicar]


Posible duplicado:
¿Cómo funciona el operador de elenco de Java?
Implementación de conversión de Java 

Siempre me pregunto cómo funciona la creación de objetos en Java. Entiendo que para el tipo primitivo será más parecido al nivel de representación binaria, pero ¿qué pasa con el Objeto? ¿Es algo así como Polymorphism o dynamic binding en que todo se determinará en tiempo de ejecución? Por ejemplo:

class Parent{
     void A(){}
}
class Child extends Parent{
     @Override
     void A(){}
}

Parent p = new Parent();
Child c = (Child) p;

¿Cómo funciona esto detrás de la escena? ¿Crea una nueva instancia de Child? Y también, qué sucede si intentas lanzar:

Child b = (Child) new Object();

Y el último, cuando se lanza una primitiva a una clase contenedora:

Double d = (Double) 3.3;

Sé que no es necesario que lo hagas, pero ¿y si lo haces? ¿Hay algo significativo que ocurra en el back-end?


32
2017-11-15 20:11


origen


Respuestas:


No se crean nuevos objetos en el sistema cuando se usa el casting explícito (excepto en su último caso, donde se emite un tipo primitivo a un contenedor de objetos, ya que double no es un objeto como Double es). Tenga en cuenta que este molde explícito no es necesario debido a Java función de autoboxing.

En tus (Child) new Object() escenario, recibirá un ClassCastException porque un Object no es un Child (aunque lo opuesto es verdad).

La respuesta a su primer escenario es la más complicada. Esencialmente, la clase padre se trata como una interfaz podría ser. Cuando lanzas el Child al Parent, Solo el Parent API está disponible. Sin embargo, el método reemplazado aún se llamará. Entonces, si lo haces:

Parent p = (Parent) new Child();
p.a();

... el Childes public void a() se llamará, aunque se lo vea a través de la lente del Parent clase. Sin embargo, si tuviera un segundo método en el Child que el Parent no tiene (digamos public void b() por ejemplo), lo harías no ser capaz de llamar a eso sin devolver el objeto a un Child.

"Detrás de escena", como dices, lo único nuevo que se crea es otra referencia de objeto que apunta al mismo objeto. Puede tener tantas referencias como desee sobre el mismo objeto singular. Considera este ejemplo:

Parent p = new Parent();
Parent p1 = p;
Parent p2 = p;
Parent p3 = p2;

Aquí, hay cuatro referencias (p, p1, p2y p3) cada uno de los cuales apunta al mismo objeto que ha creado con el new Parent() declaración.

Sin embargo, probablemente argumentaría sobre el punto filosófico, que esta creación de nuevas referencias es realmente explícita en lugar de detrás de las escenas cuando dices Parent p = something.

Campo de golf:


13
2017-11-15 20:16



La respuesta simple a tu pregunta principal es No. Todo el casting ocurre en el tiempo de comprobación de la sintaxis.

La conversión afecta la forma en que el verificador de sintaxis mira el objeto, no afecta al objeto en sí un niño fundido para ser un Padre, todavía es un Niño.

Sin embargo, el lanzamiento solo se verifica en Runtime. Por eso es peligroso y no debe usarse a menos que no haya otra manera.


9
2017-11-15 21:38



Accediendo a esto: cheque, lo que hace es verificar si la referencia es asignable. Si lo es, la pila no se cambia y la operación en esa referencia se mantiene.

Entonces si tienes:

 Child c = ( Child )  anyObject; 
 c.sayHi();

Si el éxito del reparto, entonces el método sayHi  podría ser invocado:

Si objectref se puede convertir a la clase resuelta, matriz o tipo de interfaz, la pila de operandos no se modifica; de lo contrario, la instrucción de verificación genera una ClassCastException.

Aquí está el "bytecode"

$ cat CastDemo.java 
class Parent {}
class Child extends Parent {}
class Main {
    Child c = (Child) new Parent();
}
$ javap -c Main
Compiled from "CastDemo.java"
class Main {
  Child c;

  Main();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0       
       5: new           #2                  // class Parent
       8: dup           
       9: invokespecial #3                  // Method Parent."<init>":()V
      12: checkcast     #4                  // class Child
      15: putfield      #5                  // Field c:LChild;
      18: return        
}

4
2017-11-15 20:22



En primer lugar, tenga mucho cuidado de no confundir conversión con fundición. Pueden compartir la sintaxis de la superficie, pero son procesos muy diferentes.

En Java puedes downcast un objeto a cualquier tipo, pero en el tiempo de ejecución obtendrás un ClassCastException si el objeto no es de hecho compatible con el tipo de objetivo. Esto sucede en el nivel de bytecode: hay una instrucción bytecode dedicada a downcasting.

Child c = (Child) new Object();

dará lugar incondicionalmente a una ClassCastException.

Double d = 3.3; // note: no explicit casting needed

llevará a cabo autoboxing en una instancia de Double. Entonces, aquí, se crea una nueva instancia.

Un dowcast normal y exitoso puede verse así:

Object o = "a";
String s = (String)o;

Aquí, no se crean objetos: solo el valor de o se copia en s. El valor es una referencia.


2
2017-11-15 20:15



Downcasting un objeto no le está haciendo nada a ese objeto. Detrás de escena, el compilador inyectará checkcast operación bytecode. Si p no es realmente una instancia de Child, se lanzará una excepción. De lo contrario, básicamente tiene una referencia segura (tipo) al mismo objeto con un tipo diferente y más específico.


Child b = (Child) new Object();

Esto falla con ClassCastException. JVM compara getClass() de new Object() con Child.class. Ya que Object.class no es una subclase de Child.class, se arroja la excepcion


Double d = (Double) 3.3;

Aquí, el casting ni siquiera es necesario, esto también funciona: Double d = 3.3. Detrás de escena esto se traduce a:

Double d = Double.valueOf(3.3);

Esto se conoce como Autoboxing.


1
2017-11-15 20:17