Varargs en la sobrecarga de métodos en Java

El siguiente código no comstack.

package varargspkg; public class Main { public static void test(int... i) { for (int t = 0; t < i.length; t++) { System.out.println(i[t]); } System.out.println("int"); } public static void test(float... f) { for (int t = 0; t < f.length; t++) { System.out.println(f[t]); } System.out.println("float"); } public static void main(String[] args) { test(1, 2); //Compilation error here quoted as follows. } } 

Se emite un error en tiempo de comstackción.

la referencia a la prueba es ambigua, tanto la prueba de método (int …) en varargspkg.Main y la prueba de método (float …) en varargspkg.Main match

Parece ser obvio porque los valores de los parámetros en el método llaman a la test(1, 2); puede ser promovido a int y float

Si alguno o ambos parámetros tienen el sufijo F o f , se comstack.


Sin embargo, si representamos los parámetros de recepción en la firma del método con los respectivos tipos de envoltura de la siguiente manera

 public static void test(Integer... i) { System.out.println("Integer" + Arrays.asList(i)); } public static void test(Float... f) { System.out.println("Float" + Arrays.asList(f)); } 

luego la llamada a la test(1, 2); método test(1, 2); no emite ningún error de comstackción. El método que se invocará en este caso es el que acepta un parámetro Varargs de Integer (el primero en el fragmento anterior).

¿Por qué es en este caso el error como en el primer caso no informado? Parece que el auto-boxeo y la promoción automática de tipos se aplican aquí. ¿Se aplica primero el auto boxeo para que se resuelva el error?

Los documentos de Oracle dicen:

En general, no debe sobrecargar un método varargs, o será difícil para los progtwigdores descubrir qué sobrecarga se llama.

La última oración en este enlace . Sin embargo, es para una mejor comprensión varargs.

También para agregar el código a continuación se comstack muy bien.

 public class OverLoading { public static void main(String[] args) { load(1); } public static void load(int i) { System.out.println("int"); } public static void load(float i) { System.out.println("float"); } } 

EDITAR:

La siguiente es la instantánea que indica el error de comstackción. Creé una nueva aplicación, por lo tanto, el nombre del paquete es diferente.

enter image description here

Estoy usando JDK 6.

Puede Widen o Box pero no puede hacer ambas cosas, a menos que esté boxing and widening a Object (An int to Integer (Boxing) y luego Integer to Object (Widening) es legal, ya que cada clase es una subclase de Object , por lo que es posible que el Integer se pase al parámetro de Object )

De manera similar, un int al Number también es legal (int -> Integer -> Number) Dado que Number es la superclase de Integer , es posible.

Veamos esto en tu ejemplo:

 public static void test(Integer...i) public static void test(Float...f) 

Hay algunas reglas que se siguen al seleccionar qué método sobrecargado seleccionar, cuando se combinan Boxing, Widening y Var-args:

  1. El ensanchamiento primitivo usa el argumento de método smallest posible
  2. El tipo de envoltura no se puede ensanchar a otro tipo de envoltura
  3. Puede Box desde int a Integer y ampliar a Object pero no a Long
  4. Latidos de ensanchamiento Boxeo, boxeo beats Var-args.
  5. Puede Box y luego Widen (Un int puede convertirse en Object través de Integer )
  6. No puede ampliar y luego Box (An int no puede convertirse en Long )
  7. No puede combinar var-args, con ensanchamiento o boxeo

Entonces, basado en las reglas dadas arriba:

Cuando pasa dos enteros a las funciones anteriores,

  • de acuerdo con la regla 3, primero tendrá que Widened y luego Boxed para caber en un Long , lo cual es ilegal de acuerdo con la regla 5 (No se puede ensanchar y luego Box).
  • Por lo tanto, está encasillado para almacenar en Integer var-args.

Pero en el primer caso, donde tienes métodos con var-args de tipos primitivos: –

 public static void test(int...i) public static void test(float...f) 

Entonces la test(1, 2) puede invocar ambos métodos (ya que ninguno de ellos es más adecuado para aplicar la rule 1 ): –

  • En el primer caso será var-args
  • En el segundo caso, se ampliará y luego Var-args (que está permitido)

Ahora, cuando tienes métodos con exactamente un int y un flost: –

 public static void test(int i) public static void test(float f) 

Luego, al invocar utilizando la test(1) , se sigue la regla 1, y se elige la ampliación más pequeña posible (es decir, la int donde no se necesita ningún ensanchamiento). Por lo tanto, se invocará el primer método.

Para más información, puede referirse a JLS - Method Invocation Conversion

En Java, 1 es como usted representa un int . Puede ser autoencapsulado a una instancia de Integer o promovido a float , y esto explica por qué el comstackdor no puede decidir sobre el método al que debería llamar. Pero nunca será autoencadenado en Long o Float (o cualquier otro tipo).

Por otro lado, si escribe 1F , es la representación de un float , que se puede encapsular automáticamente en un Float (y, en el mismo espíritu, nunca se autoenchufará en un Integer o cualquier otra cosa).

¿Por qué es en este caso el error como en el primer caso no informado? Parece que el auto-boxeo y la promoción automática de tipos se aplican aquí. ¿Se aplica el auto-boxing primero, se resuelve el error?

Solo una opinión: en el caso de los varargs, la JVM en realidad tiene que crear una matriz de argumentos. En el caso de Integer y Float, es obvio qué tipo de matriz debería crear. Entonces, probablemente sea la razón por la cual no hay error de ambigüedad.

Pero aún así, es un poco confuso, por qué no puede crear una matriz de enteros, cuando por defecto 1, 3 son enteros.

Parece que esto se ha discutido aquí en SO en el pasado error con varargs y sobrecarga? y de hecho es un error , según la discusión.

En Java 6, el problema radica en la instantiation de sus generics antes de encontrar qué método está disponible para llamar.

 When you write 1,2 -> it can be be both int[] or float[] and hence the issue being complained. When you write 1,2F -> it can be be only float[] and hence the NO issue being complained. 

Lo mismo con otras dos opciones, es decir,

 When you write 1F,2 -> it can be be only float[] and hence the NO issue being complained. When you write 1F,2F -> it can be be only float[] and hence the NO issue being complained. 

Por otro lado, cuando usa int o float , no hay instanciación de tipo variable. Cuando usa 1 , 1 intenta encontrar el método con int como argumento, de lo contrario, promueve el tipo e identifica el método con float. Si ambos métodos están disponibles, uno con int se usará primero.

El problema de la ambigüedad no vendrá en Java 7 ya que tiene un mejor manejo de la verificación y promoción del tipo de datos.