specific - ¿Cómo funciona Java Object casting detrás de la escena?
instanceof java (5)
Atendiendo a esto: checkcast , 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 invocarse:
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
}
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 el sentido de 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?
Downcasting un objeto no le está haciendo nada a ese objeto. Detrás de escena, el compilador inyectará la operación de checkcast
. 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()
del new Object()
con Child.class
. Como Object.class
no es una subclase de Child.class
, se lanza una excepción.
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 .
En primer lugar, tenga mucho cuidado de no confundir la conversión con el casting . Pueden compartir la sintaxis de la superficie, pero son procesos muy diferentes.
En Java puede bajar un Objeto a cualquier tipo, pero en el tiempo de ejecución obtendrá una ClassCastException
si el objeto no es de hecho compatible con el tipo de destino. 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
realizará el 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 se copia el valor de o
en s
. El valor es una referencia.
La respuesta simple a su pregunta principal es No. Todo el lanzamiento 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 elemento secundario para ser un elemento primario sigue siendo un elemento secundario.
Sin embargo, el lanzamiento solo se verifica en Runtime. Por eso es peligroso y no debe usarse a menos que no haya otra forma.
No se crean nuevos objetos en el sistema cuando se usa conversión explícita (excepto en su último caso, donde se envía un tipo primitivo a un contenedor de objetos , ya que el double
no es un objeto como el Double
). Tenga en cuenta que este lanzamiento explícito no es necesario debido a la característica de autoboxing de Java.
En su escenario (Child) new Object()
, recibirá una ClassCastException porque un Object
no es un Child
(aunque lo contrario es cierto).
La respuesta a su primer escenario es la más complicada. Esencialmente, la clase padre se trata como una interfaz podría ser. Cuando transfiere Child
a Parent
, solo está disponible Parent
API. Sin embargo, el método reemplazado seguirá siendo llamado . Entonces, si lo haces:
Parent p = (Parent) new Child();
p.a();
... se llamará el public void a()
del Child
, aunque se lo vea a través del lente de la clase de Parent
. Sin embargo, si tuviera un segundo método en el Child
que el Parent
no tiene (digamos public void b()
por ejemplo), no podría llamarlo 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
, p2
y p3
) cada una de las cuales apunta al mismo objeto que usted creó con la new Parent()
declaración new Parent()
.
Sin embargo, probablemente discutirí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:
- http://en.wikipedia.org/wiki/Primitive_wrapper_class
- http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html
- http://docs.oracle.com/javase/7/docs/api/java/lang/ClassCastException.html
- http://docs.oracle.com/javase/tutorial/java/IandI/override.html
- ¿Java es "pass-by-reference" o "pass-by-value"?