java - parameter - vararg kotlin
Varargs en la sobrecarga de métodos en Java (4)
El siguiente código no se compila.
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 compilación.
la referencia a la prueba es ambigua, tanto la prueba de método (int ...) en varargspkg.Main como la prueba de método (flotante ...) en varargspkg.Main coinciden
Parece obvio porque los valores de los parámetros en el método de test(1, 2);
Puede ser promovido a int
así como a float
Si cualquiera de los parámetros o ambos están sufijados por F
o f
, se compila.
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 compilación. El método que se debe invocar en este caso es el que acepta un parámetro de varargs Integer
(el primero en el fragmento de código anterior).
¿Por qué en este caso no se informa el error como en el primer caso? Parece que el boxeo automático y la promoción automática de tipos se aplican aquí. ¿Se aplica primero el boxeo automático para resolver el error?
La documentación de Oracle dice:
En general, no debe sobrecargar un método de varargs, o será difícil para los programadores descubrir a qué sobrecarga se llama.
La última frase en este link . Sin embargo, es por el bien de una mejor comprensión varargs.
También para agregar a continuación el código compila 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 compilación. He creado una nueva aplicación por lo que el nombre del paquete es diferente.
Estoy usando JDK 6.
¿Por qué en este caso no se informa el error como en el primer caso? Parece que el boxeo automático y la promoción automática de tipos se aplican aquí. ¿Se aplica el auto-boxeo primero se resuelve el error?
Solo una opinión: en caso de varargs, la JVM tiene que crear una serie de argumentos. En el caso de Integer y Float, es obvio qué tipo de matriz debe crear. Por lo tanto, probablemente podría ser la razón de que no haya 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 ints.
Parece que esto ha sido discutido aquí en SO en el pasado error con varargs y sobrecarga? y de hecho es un error , de acuerdo con la discusión.
En Java 6, el problema radica en el momento de la instantiation
de instantiation
de sus genéricos 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 una instanciación de tipo variable. Cuando usas 1
, 1
intenta encontrar el método con int
como argumento, si no, promueve el tipo e identifica el método con float. Si ambos métodos están disponibles, se utilizará primero uno con int
.
El problema de ambigüedad no se presentará en Java 7, ya que tiene un mejor manejo de la verificación y promoción de los tipos de datos.
En Java, 1
es cómo representas un int
. Se puede encuadrar automáticamente en una instancia de Integer
o promocionarlo a float
, y esto explica por qué el compilador no puede decidir el método al que debería llamar. Pero nunca será auto-boxeado a Long
o Float
(o cualquier otro tipo).
Por otro lado, si escribe 1F
, es la representación de un float
, que se puede encuadrar automáticamente en un Float
(y, en el mismo sentido, nunca se encasillará automáticamente en un Integer
o cualquier otra cosa).
Puede boxing and widening
pero no puede hacer ambas cosas, a menos que esté boxing and widening
a Object
(un int a Integer (Boxing) y luego Integer to Object (Widening) es legal, ya que cada clase es una subclase de Object
, por lo que es posible pasar el Integer
al parámetro Object
)
De manera similar, un int
a 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:
- La ampliación primitiva utiliza el método de argumento
smallest
posible. - El tipo de contenedor no se puede ampliar a otro tipo de contenedor
- Puede boxear desde int a entero y ensanchar a objeto pero no a largo
- Ampliación de latidos Boxeo, Boxeo de Var-args.
- Puede encajonar y luego ampliar (un
int
puede convertirse enObject
través de unInteger
) - No puedes Widen y luego Box (un
int
no puede serLong
) - No puede combinar var-args, ya sea con ampliación o boxeo
Entonces, basado en las reglas dadas anteriormente:
Cuando pasas dos enteros a las funciones anteriores,
- de acuerdo con la regla 3, primero deberá
Widened
y luego encuadrarse para que quepa en unLong
, lo cual es ilegal de acuerdo con la regla 5 (No se puede Widen y luego Box). - Por lo tanto, está en caja para almacenar en
Integer
var-args.
Pero en el primer caso, donde tiene métodos con var-args
de tipos primitivos:
public static void test(int...i)
public static void test(float...f)
Luego la test(1, 2)
puede invocar ambos métodos (ya que ninguno de ellos es más adecuado para que se aplique la rule 1
):
- En el primer caso será
var-args
- En el segundo caso, será Ampliación 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 ninguna ampliación). Así se invocará el 1er método.
Para obtener más información, puede consultar JLS - Method Invocation Conversion