method - Sobrecarga de Java-larga y flotante
method overloading c# (4)
Cita de JLS :
El proceso de determinación de la aplicabilidad comienza con la determinación de los métodos potencialmente aplicables (§15.12.2.1).
El resto del proceso se divide en tres fases, para garantizar la compatibilidad con las versiones del lenguaje de programación Java anterior a Java SE 5.0. Las fases son:
- La primera fase (§15.12.2.2) realiza la resolución de sobrecarga sin permitir la conversión de boxeo o unboxing, o el uso de invocación del método de aridad variable. Si no se encuentra un método aplicable durante esta fase, el procesamiento continúa a la segunda fase.
Esto garantiza que cualquier llamada que fuera válida en el lenguaje de programación Java anterior a Java SE 5.0 no se considerará ambigua como resultado de la introducción de métodos de aridad variable, boxeo implícito y / o unboxing. Sin embargo, la declaración de un método de aridad variable (§8.4.1) puede cambiar el método elegido para una expresión de invocación del método del método dado, porque un método de aridad variable se trata como un método de aridad fija en la primera fase. Por ejemplo, declarar m (Objeto ...) en una clase que ya declara m (Objeto) hace que m (Objeto) ya no sea elegido para algunas expresiones de invocación (como m (nulo)), como m (Objeto [] ) es más específico.
- 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 hasta la tercera fase. ...
Edición: acerca de elegir flotar en lugar de doble:
Si más de un método miembro es accesible y aplicable a una invocación de método, es necesario elegir uno para proporcionar el descriptor para el envío del método en tiempo de ejecución. El lenguaje de programación Java usa la regla de que se elige el método más específico.
La intuición informal es que un método es más específico que otro si cualquier invocación manejada por el primer método se puede pasar al otro sin un error de tiempo de compilación.
La primera fase de resolución de sobrecarga elegirá dos de estos cuatro métodos
private static void foo(double aDouble)
private static void foo(float aFloat)
porque la primera fase no permite el boxeo / desempaquetado ( Long
) y no se puede pasar long
al método con el parámetro int
sin una conversión explícita. Se elegirá el método más específico. En esta situación, el método de float
se interpretaría como más específico que double
.
Estaba tratando de entender las reglas de sobrecarga de Java. Todo parece estar bien, excepto los siguientes.
public static void main(String[] args) {
long aLong = 123L;
foo(aLong);
}
private static void foo(double aDouble) {
System.out.println("Foo aDouble");
}
private static void foo(Long aWrapperLong) {
System.out.println("Foo Wrapper Long");
}
private static void foo(int anInt) {
System.out.println("Foo Int");
}
private static void foo(float aFloat) {
System.out.println("Foo Float");
}
¿Por qué se resuelve la llamada a foo(float aFloat)
. Entiendo lo siguiente de JLS,
Este paso utiliza el nombre del método y los tipos de las expresiones de argumento para localizar métodos que sean accesibles y aplicables. Puede haber más de uno de estos métodos, en cuyo caso se elige el más específico.
He usado intencionalmente Wrapper Long aquí y no primitivo por mucho tiempo. El tamaño primitivo de 64 bits de largo no termina en foo(double aDouble)
sino en 32 bit float foo(float aFloat)
.
La pregunta ¿Por qué Java implícitamente (sin cast) convierte un `long` en un` float`? Aclara aún más la respuesta a esta pregunta.
Esto se debe a la regla ''más específica'' en JLS # 15 , que a su vez se refiere a JLS # 4.10 , que a su vez se refiere a # 4.10.1, que dice:
Las siguientes reglas definen la relación supertipo directa entre los tipos primitivos:
doble> 1 flotador
flotar> 1 largo
largo> 1 int
int> 1 char
int> 1 corto
corto> 1 byte
donde "S> 1 T" significa que "T es un subtipo directo de S", según JLS # 4.10 inmediatamente arriba de esta sección.
Entonces, en este caso, en ausencia de una coincidencia directa por long
, y antes de mirar el boxeo automático, el compilador elige el supertipo disponible más cercano, que es float
, según las reglas anteriores.
La ampliación tiene prioridad antes del autoboxing para la sobrecarga. Las clases Wrapper para primitivas (Integer, Long, etc.) no se introdujeron en Java desde el principio, y debido a que Java es compatible con versiones anteriores, debe ejecutar el código que se escribió en una versión de Java de la misma manera en las versiones más nuevas.
La conversión tiene reglas de precedencia. Se elegirá la ampliación sobre el boxeo .
Entonces, en este caso, el compilador busca un método que pueda aceptar el parámetro más grande (más cercano posible más grande) que el tipo de datos primitivos largos como un argumento, que es flotante.
Si elimina los métodos foo (doble aDouble) y foo (float aFloat) de su ejemplo publicado, el compilador realizará el boxeo y elegirá foo (Long aWrapperLong)