Pasar argumentos de bytes al método sobrecargado

12

Tomé este fragmento de código de alguna prueba, usando IDE, lo ejecuté y obtuve un resultado largo, largo, pero la respuesta correcta es Byte, Byte , ¿por qué obtuve un resultado diferente? La pregunta está relacionada con JDK 11

public class Client {
    static void doCalc(byte... a) {
        System.out.print("byte...");
    }

    static void doCalc(long a, long b) {
        System.out.print("long, long");
    }

    static void doCalc(Byte s1, Byte s2) {
        System.out.print("Byte, Byte");
    }

    public static void main(String[] args) {
        byte b = 5;
        doCalc(b, b);
    }
}

EDITADO:

El código se tomó aquí: Descripción general de la certificación de Oracle y preguntas de muestra (Página: 13, Pregunta: 5)

kbo
fuente
1
¿Estás seguro de que no es Byte b = 5;con un capital B.
Joop Eggen
44
Me meto long, longen Java8 también FYI ... No estoy seguro de por qué para ser honesto, esperando una respuesta también :)
sp00m
Posible duplicado de la sobrecarga del método Java con boxeo / ampliación
Pavel Smirnov

Respuestas:

6

Por lo tanto, si se va por el lenguaje Java especificación para la determinación de método de firma en tiempo de compilación será claro:

  1. La primera fase (§15.12.2.2) realiza la resolución de sobrecarga sin permitir la conversión de boxing o unboxing o el uso de la invocación del método de arity variable. Si no se encuentra ningún método aplicable durante esta fase, el procesamiento continúa a la segunda fase.

  2. La segunda fase (§15.12.2.3) realiza la resolución de sobrecarga al tiempo que permite el boxeo y el desempaquetado, pero aún impide el uso de la invocación del método de aridad variable. Si no se encuentra ningún método aplicable durante esta fase, el procesamiento continúa a la tercera fase.

  3. La tercera fase (§15.12.2.4) permite que la sobrecarga se combine con métodos de arity variables, boxing y unboxing.

Entonces, de los pasos anteriores, está claro que en su caso en la primera fase, el compilador de Java encontrará un método de coincidencia que sí lo hace doCalc(long a,long b). Su método doCalc(Byte s1, Byte s2)necesita un autoboxing durante la llamada, por lo que tendrá menos preferencia.

Amit Bera
fuente
1
En cuanto a por qué longacepta byte, parece seguir una conversión primitiva cada vez mayor : docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.2 . Básicamente, +widening -boxing -varargsentonces , +widening +boxing -varargsentonces +widening +boxing +varargs.
sp00m
@kbo ¿Por qué crees que la respuesta correcta es Byte, Byte?
Amit Bera
3
@kbo Supongo que la respuesta correcta es incorrecta :) Merecería la pena señalar a los autores esta pregunta si puedes.
sp00m
3
@ sp00m Encontré esta pregunta en las muestras de Oracle, eche un vistazo a la parte editada
kbo
@kbo Wow ... ¡No tengo idea de cómo proceder entonces!
sp00m
2

Lea el capítulo de JLS sobre conversiones .

Lo que sucede en su caso es que durante el tiempo de ejecución, JVM elige realizar una conversión de ampliación, byte -> long ya que esta conversión es más segura porque se garantiza que no causa RuntimeException.

La conversión de bytea Bytetambién llamado boxing puede resultar en OutOfMemoryError ya que la JVM tiene que asignar nuevos objetos al montón:

Una conversión de boxeo puede dar lugar a un OutOfMemoryError si se necesita asignar una nueva instancia de una de las clases de contenedor (booleano, byte, carácter, corto, entero, largo, flotante o doble) y no hay suficiente almacenamiento disponible.

Por eso, se prefiere la byte -> long conversión de ampliación más segura .

diginoise
fuente
2
Solo para tener en cuenta, el boxeo de bytea Bytenunca causa OutOfMemoryException, ya que todos los valores de Byte(-128-127) se almacenan en caché internamente. Pero puede no ser lo mismo con otros tipos, por lo que, como regla general, la ampliación de la conversión tiene prioridad.
Pavel Smirnov
1

Para encontrar la sobrecarga correcta, el orden es:

  1. por número de parámetros
  2. boxeo / unboxing
  3. parámetros variadic

Entonces

  • Si bdonde un Byteresultado sería Byte, Byte.
  • Si se hubiera aprobado, new byte[] { b, b }el resultado sería byte, byte.
  • Si pasa dos bytes b, es posible un ensanchamiento de byte a int a largo y el resultado es long, long.
  • Cuando se elimina la sobrecarga larga, larga, Byte, Byteresulta.
Joop Eggen
fuente