que - Java: selección entre constructores sobrecargados
sobrecarga de metodos en java (3)
Este comportamiento se debe a que E no es más específico que A, ya que pertenecen a jerarquías diferentes, no se pueden comparar. Por lo tanto, cuando pasa un nulo, Java no puede saber qué jerarquía usar.
Según esta pregunta , Java seleccionará la opción "más específica" cuando intente seleccionar entre constructores sobrecargados ambiguos. En este ejemplo:
public class Test{
private Test(Map map){
System.out.println("Map");
}
private Test(Object o){
System.out.println("Object");
}
public static void main(String[] args){
new Test(null);
}
}
se imprimirá
"Mapa"
Sin embargo, estaba tratando de averiguar exactamente qué significa "más específico". Supuse que significaba "menos ambiguo", como en "puede referirse al menor número posible de tipos". En este contexto, Object
puede ser cualquier cosa que no sea primitiva, mientras que Map
puede ser solo Map
o ? extends Map
? extends Map
. Básicamente, asumí que cualquier clase que estuviera más cerca de la hoja del árbol de herencia sería seleccionada. Eso funciona cuando una clase es una subclase de la otra:
public class Test{
private Test(A a){
System.out.println("A");
}
private Test(B b){
System.out.println("B");
}
public static void main(String[] args){
new Test(null);
}
}
class A{}
class B extends A{}
"SEGUNDO"
Entonces se me ocurrió esto:
public class Test{
private Test(A a){
System.out.println("A");
}
private Test(E e){
System.out.println("E");
}
public static void main(String[] args){
new Test(null);
}
}
class A{}
class B extends A{}
class C{}
class D extends C{}
class E extends D{}
Creo que debería imprimir E
, ya que E
solo puede referirse a un tipo conocido, mientras que A
puede referirse a dos ( A
y B
). Pero da un error de referencia ambiguo.
¿Cómo es realmente elegir el constructor? Leí los documentos pero, francamente, no pude entender cómo determina la especificidad. Espero una descripción de por qué no puede determinar que E
es más específico que A
La siguiente declaración de 15.12.2.5 responde que,
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 podría pasarse a la otra sin un error en tiempo de compilación.
Caso 1
- Puede pasar cualquier cosa en el constructor que toma
Object
mientras que no podemos pasar nada que no sea unMap
en el primer constructor. Así que todo lo que paso en el constructor delMap
puede ser manejado por el constructor delObject
y es por eso que elTest(Map map)
vuelve mote específico.
Caso 2
- Como
B
extiendeA
, aquíTest(B b)
constructor deTest(B b)
vuelve más específico. Como podemos pasarB
enTest(A a)
gracias a la herencia .
Caso 3
- En este caso, no hay una conversión directa para representar el método más específico y resulta en ambigüedad .
No se basa en la cantidad de tipos que son convertibles en el tipo de parámetro, sino en que cualquier valor válido para una sobrecarga sea válido para otro debido a conversiones implícitas.
Por ejemplo, hay una conversión implícita de String
a Object
, pero el reverso no es verdadero, por lo que String
es más específico que Object
.
Del mismo modo, hay una conversión implícita de B
a A
, pero el reverso no es verdadero, por lo que B
es más específico que A
Sin embargo, con A
y E
, ninguno es más específico que el otro, no hay conversión de A
a E
ni conversión de E
a A
Es por eso que la resolución de sobrecarga falla.
El bit relevante del JLS es en realidad 15.12.2.5 , que incluye esto que podría facilitar su comprensión:
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 podría pasarse a la otra sin un error en tiempo de compilación.
Entonces si tienes:
void foo(String x)
void foo(Object x)
cada invocación manejada por foo(String)
podría ser manejada por foo(Object)
, pero lo contrario no es el caso. (Por ejemplo, podría llamar a foo(new Object())
y eso no podría ser manejado por foo(String)
.)