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.
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:
smallest
posible int
puede convertirse en Object
través de Integer
) int
no puede convertirse en Long
) Entonces, basado en las reglas dadas arriba:
Cuando pasa dos enteros a las funciones anteriores,
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). 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
): –
var-args
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.