Método de sobrecarga para argumento nulo

133

He agregado tres métodos con parámetros:

public static  void doSomething(Object obj) {
    System.out.println("Object called");
}

public static  void doSomething(char[] obj) {
    System.out.println("Array called");
}

public static  void doSomething(Integer obj) {
    System.out.println("Integer called");
}

Cuando llamo doSomething(null), el compilador arroja el error como métodos ambiguos . Entonces, ¿es el problema porque Integery los char[]métodos o Integery los Objectmétodos?

Phani
fuente
3
Solo cambia el Integera int.
Mudassir
2
@Mudassir: ¿y qué resolvería eso exactamente?
Joachim Sauer
2
@Joachim Sauer: si se cambia de Integer a int, entonces nulo no se refiere a tipos primitivos en Java, por lo que el compilador no arrojará errores.
Phani
@Joachim Sauer: No arrojará el reference to doSomething is ambiguouserror.
Mudassir

Respuestas:

211

Java siempre intentará usar la versión aplicable más específica de un método que esté disponible (consulte JLS §15.12.2 ).

Object, char[]y Integertodos pueden tomarse nullcomo un valor válido. Por lo tanto, las 3 versiones son aplicables, por lo que Java tendrá que encontrar la más específica.

Como Objectes el supertipo de char[], la versión de matriz es más específica que la Objectversión. Entonces, si solo existen esos dos métodos, char[]se elegirá la versión.

Cuando están disponibles las versiones char[]y Integer, ambas son más específicas que Objectninguna, pero ninguna es más específica que la otra, por lo que Java no puede decidir a cuál llamar. En este caso, tendrá que mencionar explícitamente a cuál desea llamar enviando el argumento al tipo apropiado.

Tenga en cuenta que en la práctica este problema ocurre mucho más raramente de lo que uno podría pensar. La razón de esto es que solo sucede cuando está llamando explícitamente a un método con nullo con una variable de un tipo bastante inespecífico (como Object).

Por el contrario, la siguiente invocación sería perfectamente inequívoca:

char[] x = null;
doSomething(x);

Aunque todavía está pasando el valor null, Java sabe exactamente a qué método llamar, ya que tendrá en cuenta el tipo de variable.

Joachim Sauer
fuente
1
Esto se indica para Java 7. ¿Eso también se aplica a las versiones anteriores de Java? Quiero decir: si tiene varias firmas de métodos con parámetros solo a lo largo de una jerarquía de tipos, ¿está en el lado de guardar con nulo como valor real? Y si ha creado una "jerarquía para" como en el ejemplo aquí, ¿entonces no es así?
Christian Gosch
2
Estoy bastante seguro de que esas reglas son las mismas para al menos todo desde Java 1.1 (excepto la adición de genéricos, obviamente).
Joachim Sauer
¿Esto significa que si el compilador eligiera entre doSomething (String str) y doSomething (Object obj) durante el tiempo de ejecución con doSomething (null), se llamará a doSomething (String str).
Sameer
42

Cada par de estos tres métodos es ambiguo en sí mismo cuando se llama con un nullargumento. Porque cada tipo de parámetro es un tipo de referencia.

Las siguientes son las tres formas de llamar a un método específico suyo con nulo.

doSomething( (Object) null);
doSomething( (Integer) null);
doSomething( (char[]) null);

¿Puedo sugerir eliminar esta ambigüedad si realmente planea llamar a estos métodos con nullargumentos? Tal diseño invita a errores en el futuro.

jmg
fuente
1
Solo Integer: el char[]par es ambiguo, porque en otros dos casos, el compilador de Java puede elegir la opción más específica, como se describe en @JoachimSauer.
kajacx
1
@kajacx: ​​La pregunta original de los OP era sobre llamar a estos métodos nullcomo parámetro. Bajo esa precondición, los tres pares son ambiguos. Para el caso general, estoy de acuerdo en que solo el Integer - char[]par es ambiguo.
jmg
¿Qué pasa doSomething(null)con public static void doSomething(String str) { System.out.println("String called"); } Esto devolverá la cadena llamada.
Sameer
¿Es posible usar una anotación como "anulable" o "no anulable" y configurar las declaraciones para que solo el método con el que desea obtener un valor nulo de modo que un argumento explícito "nulo" (sin embargo, tipo nulo implícito) siempre seleccione inequívocamente una sobrecarga específica ??
peterk
4

nulles un valor válido para cualquiera de los tres tipos; entonces el compilador no puede decidir qué función usar. Use algo como doSomething((Object)null)o en su doSomething((Integer)null)lugar.

Lars Noschinski
fuente
Eliminé el método con el parámetro Integer, invoca la función y devuelve la salida como "Array Called" , ¿cuál es el contrato entre Array y Object ?
Phani
2
Las matrices de Java también son objetos.
Zds
2

Cada clase en Java extiende la clase Object. Incluso la clase Integer también extiende Object. Por lo tanto, tanto Object como Integer se consideran como instancia de Object. Entonces, cuando pasa nulo como parámetro, el compilador se confunde a qué método de objeto llamar, es decir, con parámetro Objeto o parámetro Entero, ya que ambos son objeto y su referencia puede ser nula. Pero las primitivas en java no extienden Object.

Ankit
fuente
1

He intentado esto y cuando hay exactamente un par de métodos sobrecargados y uno de ellos tiene un tipo de parámetro Object, el compilador siempre seleccionará el método con un tipo más específico. Pero cuando hay más de un tipo específico, el compilador arroja un error de método ambiguo.

Dado que este es un evento de tiempo de compilación, esto solo puede suceder cuando uno intencionalmente pasa nulo a este método. Si esto se hace intencionalmente, es mejor sobrecargar este método nuevamente sin ningún parámetro o crear otro método por completo.

Jafar Ali
fuente
0

existe una ambigüedad debido a doSomething (char [] obj) y doSomething (Integer obj).

char [] e Integer son superiores para nulo, por eso son ambiguos.

Chitrendra Chaudhary
fuente
0
class Sample{
  public static void main (String[] args) {
       Sample s = new Sample();
       s.printVal(null);

    } 
    public static void printVal(Object i){
        System.out.println("obj called "+i);
    }

    public static void printVal(Integer i){
        System.out.println("Int called "+i);
    }
}

El resultado es Int llamado nulo y la ambigüedad es con char [] e Integer

nagarjuna chimakurthi
fuente