2011-12-21 16 views
8

Digamos que tengo una clase Fraction:¿Por qué el siguiente código se traduce en una nueva instrucción + dup op en bytecode java?

class Fraction { 
    ... 

    /** Invert current fraction */ 
    public Fraction inverse() { 
     return new Fraction(den,num); 
    } 

    ... 
} 

Y esto es lo que el código de bytes del método anterior resulta ser:

0 new #1 <xyzTestes/system/fraction/Fraction> 
3 dup 
4 aload_0 
5 getfield #16 <xyzTestes/system/fraction/Fraction.den> 
8 aload_0 
9 getfield #14 <xyzTestes/system/fraction/Fraction.num> 
12 invokespecial #27 <xyzTestes/system/fraction/Fraction.<init>> 
15 areturn 

Estoy tratando de entender por qué la instrucción en la posición 3 fue puesto allí en primer lugar. Yo diría que solo tendríamos que hacer lo siguiente para que funcione:

new #1 <xyzTestes/system/fraction/Fraction> 
aload_0 
getfield #16 <xyzTestes/system/fraction/Fraction.den> 
aload_0 
getfield #14 <xyzTestes/system/fraction/Fraction.num> 
invokespecial #27 <xyzTestes/system/fraction/Fraction.<init>> 
areturn 

¿Por qué no es así?

Respuesta

10

Cuando se inicia el bytecode para el constructor, no hay objeto Fraction. La instrucción new asigna un objeto Fraction (no inicializado) del montón y deja una referencia en la pila. La instrucción dup es para que una referencia se pueda usar para llamar a <init> y la segunda para el areturn al final.

+0

invokespecial no pondrá una referencia a la Fracción en la pila, entonces? –

+5

@devoured elysium '() V' devuelve' void' no 'Fraction'. –

+0

Meh, tienes razón. –

8

Su bytecode es incorrecto. Demos un paso a través de él:

new #1 <xyzTestes/system/fraction/Fraction> 

Pila: Fraction instancia (no inicializado, solamente un puntero a la memoria)

aload_0 

Pila: Fraction (todavía no inicializado), this

getfield #16 <xyzTestes/system/fraction/Fraction.den> 

Pila: Fraction (todavía no inicializado), this.den

aload_0 
getfield #14 <xyzTestes/system/fraction/Fraction.num> 

Pila: Fraction (todavía no inicializado), this.den, this.num

invokespecial #27 <xyzTestes/system/fraction/Fraction.<init>> 

Pila:

Esto es crucial. Todos los métodos invoke requieren que la pila contenga this + todos los argumentos. Ambos this y argumentos se toman de la pila. Después de la invocación, solo se coloca un valor de retorno (si lo hay) en la pila. <init> tiene un tipo de devolución void.

Esto significa que se llame:

areturn 

En una pila vacía, apagando la JVM.

Cuestiones relacionadas