Java: selección entre constructores sobrecargados


Por esta pregunta, Java seleccionará la opción "más específica" cuando intente seleccionar entre constructores ambiguos sobrecargados. 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". Asumí que significaba "menos ambiguo", como en " puede referirse a la menor cantidad de tipos posibles."En este contexto, Object puede ser cualquier cosa que no sea primitiva, mientras que Map solo puede ser Map o ? extends Map. Básicamente, asumí que se seleccionaría cualquier clase que estuviera más cerca de la hoja del árbol de herencia. 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{}

" B "

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 en realidad la elección de la constructor? Leí los documentos pero francamente no pude entender cómo determina la especificidad. Espero una descripción de exactamente por qué no puede determinar que E es más específico que A.

Author: Community, 2016-08-16

3 answers

No se basa en el número de tipos que son convertibles al tipo de parámetro - se trata de si cualquier valor que es válido para una sobrecarga es válido para otro, debido a conversiones implícitas.

Por ejemplo, hay una conversión implícita de String a Object, pero lo contrario no es cierto, 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 lo contrario no es cierto, por lo que B es más específico que A.

Con A y E sin embargo, ninguno es más específico que el otro - no hay conversión de A a E, y no hay conversión de E a A. Es por eso que falla la resolución de sobrecarga.

El bit relevante de la JLS es en realidad 15.12.2.5, que incluye esto que podría hacer que sea más fácil para usted entender:

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 otro sin error en tiempo de compilación.

Así que 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ías llamar a foo(new Object()) y eso no podría ser manejado por foo(String).)

 45
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-16 16:28:11

Tras la declaración de la JSL§15.12.2.5 responde que,

La intuición informal es que un método es más específico que otro si se puede pasar cualquier invocación manejada por el primer método a la otra sin un error en tiempo de compilación.

Caso 1

  • Puede pasar cualquier cosa en constructor que tome Object mientras que nosotros no podemos pasar nada que no sea un Map en el primer constructor. Tan lo que pase en Map constructor puede ser manejado por Object constructor y es por eso que Test(Map map) se convierte en mote específico.

Caso 2

  • Dado que B se extiende A, aquí Test(B b) constructor se vuelve más específico. Como podemos pasar {[5] {} en[9]} gracias a herencia.

Caso 3

  • En este caso no hay conversión directa para representar el método más específico y resulta en ambigüedad.
 9
Author: coder-croc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-16 16:39:20

Este comportamiento se debe a que E no es más específico que A, ya que pertenecen a diferentes jerarquías que no se pueden comparar. Por lo tanto, cuando se pasa un null, Java no puede saber qué jerarquía usar.

 6
Author: Jordi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-16 16:24:53