2015-11-01 6 views
11

scelta Ho un due metodi di overload: foo e barsovraccarico varargs array, metodo

//Object[]... vs Integer[]... 
public static String foo(Object[]... args) { return "Object[] args"; } 
public static String foo(Integer[]... args) { return "Integer[] args";} 

//Object... vs Integer[]... 
public static String bar(Object... args) {return "Object args";} 
public static String bar(Integer[]... args) {return "Integer[] args";} 

Ora, quando li uso come:

Integer[] i = { 5 }; 
System.out.println(foo(i));//Object[]... vs Integer[]... 
System.out.println(bar(i));//Object... vs Integer[]... 

sto ottenendo

Integer[] args 
Object args 

Ecco la domanda: perché abbiamo 2 uscite differenti?
Integer[] può essere convertito implicitamente in Object e Object[].

+2

Per coloro che vogliono giocare a Sherlock [15.12.2.5. Scelta del metodo più specifico] (https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5) – Pshemo

+0

dovresti menzionare almeno l'avviso del compilatore. –

+0

@ Colonel, sì puoi e si puoi. Otterrai un'eccezione di runtime quando lo proverai. –

risposta

3

Questo è fondamentalmente il compilatore che decide di chiamare il metodo più specifico tra tutti.

Quando si chiama

System.out.println(foo(i));//Object[]... vs Integer[]... 

si chiamerà il foo(Integer[]... args)

Poiché in fase di esecuzione i delegati JVM la chiamata al metodo con Integer[][] argomento e non il metodo con Object[][] param come specificato da varags . Come sarà più specifico chiamare metodo con Intero [] [] piuttosto che Oggetto [] [].


Nella dichiarazione successiva, quando si chiama

System.out.println(bar(i));//Object... vs Integer[]...

si andrà al bar(Object... args)

nuovamente utilizzando varags, il tipo di parametro è Object [] e non Oggetto[][]. Di nuovo il compilatore chiamerà il metodo più specifico che sarà quello che ha Object... args.

Se si modifica la firma del metodo rimuovendo varags secondo il seguente:

//Object... vs Integer[]... 
    public static String bar(Object args) { 

     return "Object args"; 
    } 

    public static String bar(Integer[] args) { 
     return "Integer[] args"; 
    } 

allora si noterà che chiamerà il bar(Integer[] args) in quanto è più specifico per la chiamata al metodo.

Quindi, per essere più precisi secondo JLS Subtyping among Array Types,

  • Se S e T sono entrambi i tipi di riferimento, quindi S []> T [] sse S> T.
  • Object> Object []

Ciò significa che una chiamata di integer [] sarà fatta procedimento avente integer [] [] e non Object [] []. Dove una chiamata di Integer [] verrà eseguita su Object [] anziché su Integer [] [].

Vedere here per scegliere il metodo più specifico.

3

Nel primo caso, il tipo di arg è in realtà intero [] [], vale a dire, l'array è stato inserito in un altro array mediante varargs. Il compilatore sceglie la versione Integer [] perché è il tipo più specifico.

Nel secondo caso, args == i ed è un numero intero []. In questo caso, il compilatore doveva scegliere tra l'inserimento in un nuovo array per chiamare la versione Integer [] ... o semplicemente il cast dell'intero [] su un oggetto []. Ha scelto il secondo perché questa è la regola.

La morale della storia è: non sovraccaricare i metodi varargs - è confuso.

+1

Riesci a trovare il bit della specifica che dice "questa è la regola"? –

+0

Potrei ... ma l'OP lo ha già dimostrato con il suo compilatore :) –

+0

Se riesci a trovarlo, prevarrò. Sto avendo problemi a decifrarlo. –