2008-08-07 19 views
26

vi esto en an answer to another question, en referencia a las deficiencias de la especificación Java:¿Esto realmente se está ampliando frente al autoboxing?

hay más carencias y esto es un tema sutil. Compruebe a cabo this:

public class methodOverloading{ 
    public static void hello(Integer x){ 
      System.out.println("Integer"); 
    } 

    public static void hello(long x){ 
      System.out.println("long"); 
    } 

    public static void main(String[] args){ 
     int i = 5; 
     hello(i); 
    } 
} 

Aquí "largo" que se va a imprimir (no se han comprobado yo mismo), porque el compilador choses> ensanchamiento sobre autoboxing. ¡Tenga cuidado al usar el autoboxing o no lo use en absoluto!

¿Estamos seguros de que esto es realmente un ejemplo de ensanchamiento en lugar de autoboxing, o es algo totalmente diferente?

En mi exploración inicial, estoy de acuerdo con la afirmación de que la salida sería "larga" sobre la base de que i se declaró como una primitiva y no como un objeto. Sin embargo, si ha cambiado

hello(long x) 

a

hello(Long x) 

la salida imprimiría "Entero"

lo que realmente está pasando aquí? No sé nada sobre los compiladores/intérpretes de bytecode para Java ...

+0

Ciertamente está ensanchándose. Int se amplía a largo. – EJP

Respuesta

12

En el primer caso, tiene lugar una conversión de ampliación. Esto se puede ver cuando runinng el programa "javap" utilidad (incluido w/JDK), en la clase compilada:

public static void main(java.lang.String[]); 
    Code: 
    0: iconst_ 5 
    1: istore_ 1 
    2: iload_ 1 
    3: i2l 
    4: invokestatic #6; //Method hello:(J)V 
    7: return 

} 

Claramente, se ve la I2L, que es la tecla de acceso para el ensanchamiento Entero-To- Instrucción de bytecode largo. Ver referencia here.

Y en el otro caso, en sustitución del "largo x" con el objeto "de largo x" firma, tendrá este código en el método principal:

public static void main(java.lang.String[]); 
    Code: 
    0: iconst_ 5 
    1: istore_ 1 
    2: iload_ 1 
    3: invokestatic #6; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 
    6: invokestatic #7; //Method hello:(Ljava/lang/Integer;)V 
    9: return 

} 

Así se ve el compilador ha creado la instrucción Integer.valueOf (int), para encapsular la primitiva dentro del wrapper.

+5

Creo que es obvio que Java tiene que ampliarse antes del auto-boxing porque el código anterior dependía de la ampliación y se rompería si ese código cambiara repentinamente a auto-boxing. –

3

Sí, pruébalo en una prueba. Verá impreso "largo". Se está ampliando porque Java elegirá ampliar el int en mucho antes de que elija autoboxearlo en un Entero, por lo que se elige el método de saludo (largo).

Editar: the original post being referenced.

Modificación adicional: El motivo por el que la segunda opción se imprime Entero es porque no hay una "ampliación" en una primitiva más grande como una opción, por lo que DEBE empaquetarla, por lo tanto, Entero es la única opción. Además, java solo se autoboxeará al tipo original, por lo que daría un error de compilación si deja el saludo (Largo) y el saludo eliminado (Entero).

1

Otra cosa interesante con este ejemplo es la sobrecarga del método. La combinación de ampliación de tipos y sobrecarga de métodos solo funciona porque el compilador tiene que tomar una decisión sobre qué método elegir.Consideremos el siguiente ejemplo:

public static void hello(Collection x){ 
    System.out.println("Collection"); 
} 

public static void hello(List x){ 
    System.out.println("List"); 
} 

public static void main(String[] args){ 
    Collection col = new ArrayList(); 
    hello(col); 
} 

No utiliza el tipo de tiempo de ejecución que está lista, se utiliza el tipo en tiempo de compilación, que es la colección y por lo tanto "Colección" impresiones.

Animo a que lea Effective Java, que me abrió los ojos a algunos casos de esquina de la JLS.

Cuestiones relacionadas