Resolución de sobrecarga de método en java

Esto es lo que sé sobre la resolución de sobrecarga en Java:


El proceso de comstackción que intenta resolver la llamada a un método a partir de definiciones de método sobrecargadas se denomina resolución de sobrecarga. Si el comstackdor no puede encontrar la coincidencia exacta, busca la coincidencia más cercana utilizando únicamente las upcasts (las upcasts descendentes nunca se realizan).


Aquí hay una clase:

 public class MyTest { public static void main(String[] args) { MyTest test = new MyTest(); Integer i = 9; test.TestOverLoad(i); } void TestOverLoad(int a){ System.out.println(8); } void TestOverLoad(Object a){ System.out.println(10); } } 

Como se esperaba, la salida es 10.

Sin embargo, si cambio ligeramente la definición de clase y cambio el segundo método sobrecargado.

  public class MyTest { public static void main(String[] args) { MyTest test = new MyTest(); Integer i = 9; test.TestOverLoad(i); } void TestOverLoad(int a){ System.out.println(8); } void TestOverLoad(String a){ System.out.println(10); } } 

La salida es 8.

Aquí estoy confundido. Si el downcasting nunca se usara, ¿por qué 8 se imprimieron? ¿Por qué el comstackdor TestOverLoad método TestOverLoad que toma int como un argumento que es un downcast de Integer a int?

El comstackdor considerará no una conversión desalentada, sino una conversión de unboxing para resolución de sobrecarga. Aquí, el Integer i se desempaquetará a una int éxito. El método de String no se considera porque un Integer no se puede ensanchar a una String . La única sobrecarga posible es la que considera unboxing, por lo que se imprime 8 .

La razón por la que el resultado del primer código es 10 es que el comstackdor considerará una conversión de referencia de ampliación ( Integer a Object ) sobre una conversión de unboxing.

La Sección 15.12.2 del JLS , al considerar qué métodos son aplicables, establece:

  1. 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 la invocación de método de aridad variable. Si no se encuentra ningún método aplicable durante esta fase, el procesamiento continúa hasta la segunda fase.
  1. La segunda fase (§15.12.2.3) realiza la resolución de sobrecarga al tiempo que permite el boxeo y el desempaquetado […]

En Java, los métodos de resolución en caso de sobrecarga de métodos se realizan con la siguiente precedencia:

1. Ensanchamiento
2. Auto-boxing
3. Var-args

El comstackdor de Java piensa que ampliar un parámetro primitivo es más deseable que realizar una operación de auto-boxeo.

En otras palabras, como se introdujo el auto-boxing en Java 5, el comstackdor elige el estilo anterior ( ensanchamiento ) antes de elegir el estilo más nuevo ( auto-boxing ), manteniendo el código existente más robusto. Lo mismo es con var-args .

En su primer fragmento de código, la ampliación de la variable de referencia ocurre, es decir, Integer a Object lugar de des-boxeo, es decir, Integer a int . Y en su segundo fragmento, la ampliación no puede pasar de Integer a String por lo que se produce un desempaquetado.

Considere el siguiente progtwig que demuestra todas las declaraciones anteriores:

 class MethodOverloading { static void go(Long x) { System.out.print("Long "); } static void go(double x) { System.out.print("double "); } static void go(Double x) { System.out.print("Double "); } static void go(int x, int y) { System.out.print("int,int "); } static void go(byte... x) { System.out.print("byte... "); } static void go(Long x, Long y) { System.out.print("Long,Long "); } static void go(long... x) { System.out.print("long... "); } public static void main(String[] args) { byte b = 5; short s = 5; long l = 5; float f = 5.0f; // widening beats autoboxing go(b); go(s); go(l); go(f); // widening beats var-args go(b, b); // auto-boxing beats var-args go(l, l); } } 

El resultado es:

  doble doble doble doble int, int larga, larga 

Solo como referencia, aquí está mi blog sobre la sobrecarga de métodos en Java .

PD: Mi respuesta es una versión modificada de un ejemplo dado en SCJP.

ensanchamiento beats boxeo, boxeo beats var-args. En su ejemplo, la ampliación no puede suceder, por lo que se aplica el boxeo y se desenlaza el entero. Nada extraordinario.

En realidad, en el segundo ejemplo, no se produjo una bajada. Ocurrió lo siguiente:

1. El entero se desenvuelve / desempaqueta al tipo primitivo int .
2. Luego se llama al método TestOverLoad(int a) .

En el método principal declaras Entero como –

  Integer i = 9; 

Luego llame –

 test.TestOverLoad(i); 

Considerando que tienes 2 versiones sobrecargadas de TestOverLoad()

 TestOverLoad(int a); TestOverLoad(String a); 

Aquí, la segunda versión sobrecargada de TestOverLoad() toma un argumento completamente diferente. Es por eso que Integer i se desempaqueta en un tipo primitivo int y luego se llama a la primera versión sobrecargada.

Todos los objetos en Java extienden la clase Object, incluida la clase Integer. Estas dos clases tienen la siguiente relación: Entero “es un (n)” Objeto porque el Entero extiende el Objeto. En su primer ejemplo, se usa el método con el parámetro Object.

En el segundo ejemplo, no se encuentran métodos que acepten un Entero. En este caso, Java usa lo que se denomina auto-unboxing para resolver la clase contenedora Integer a una primitiva int. Por lo tanto, se utiliza el método con el parámetro int.