Pregunta

Vi esto en una respuesta a otra pregunta, en referencia a las deficiencias de la especificación de Java:

Hay más deficiencias y este es un tema sutil.Controlar este afuera:

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í se imprimiría "largo" (no lo he comprobado yo mismo), porque el compilador elige ampliar en lugar de encuadrar automáticamente.¡Ten cuidado al usar el boxeo automático o no lo uses en absoluto!

¿Estamos seguros de que este es realmente un ejemplo de ampliación en lugar de autoboxing, o es algo completamente distinto?

En mi escaneo inicial, estoy de acuerdo con la afirmación de que el resultado sería "largo" en base a i siendo declarado como un primitivo y no como un objeto.Sin embargo, si cambiaste

hello(long x)

a

hello(Long x)

la salida imprimiría "Entero"

¿Qué está pasando realmente aquí?No sé nada sobre los compiladores/intérpretes de código de bytes para Java...

¿Fue útil?

Solución

En el primer caso, se está produciendo una conversión cada vez más amplia.Esto se puede ver al ejecutar el programa de utilidad "javap" (incluido con el 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, ve el I2L, que es el mnemotécnico para la instrucción de código de bytes de ampliación de entero a largo.Ver referencia aquí.

Y en el otro caso, reemplazando la "x larga" con la firma del objeto "x larga", tendrás 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

}

Entonces verá que el compilador ha creado la instrucción Integer.valueOf(int), para encuadrar la primitiva dentro del contenedor.

Otros consejos

Sí lo es, pruébalo en una prueba.Verá impreso "largo".Se está ampliando porque Java elegirá ampliar el int a long antes de elegir autoboxearlo a un entero, por lo que se elige llamar al método hello(long).

Editar: la publicación original a la que se hace referencia.

Edición adicional:La razón por la que la segunda opción imprimiría Integer es porque no hay una "ampliación" a una primitiva más grande como opción, por lo que DEBE encajonarla, por lo que Integer es la única opción.Además, Java solo se ajustará automáticamente al tipo original, por lo que daría un error de compilación si deja hola (Long) y elimina hola (Integer).

Otra cosa interesante de este ejemplo es la sobrecarga de métodos.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.Considere 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 usa el tipo de tiempo de ejecución que es Lista, usa el tipo de tiempo de compilación que es Colección y por lo tanto imprime "Colección".

te animo a leer Java efectivo, lo que me abrió los ojos sobre algunos casos extremos del JLS.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top