2016-05-19 27 views
11

Si consideri il seguente codice di esempio:Java sovraccarico: riferimento a chiamare ambiguo

public class TestClass { 

    public void doSth(String str, String l, Object... objects) { 
     System.out.println("A"); 
    } 

    public void doSth(String str, Object... objects) { 
     System.out.println("B"); 
    } 

} 

Quando io ora chiamo new TestClass().doSth("foo", "bar") ottengo il risultato atteso A. Ma se cambio la firma del metodo del primo metodo con il parametro chaging l ad un tipo primitivo:

public class TestClass { 

    public void doSth(String str, long l, Object... objects) { 
     System.out.println("A"); 
    } 

    public void doSth(String str, Object... objects) { 
     System.out.println("B"); 
    } 

} 

chiamando new TestClass().doSth("foo", 2L) darà un errore di tempo reference to call ambiguous compilazione.

Ho pensato a quello per un po 'di tempo e ho anche consultato lo this stackoverflow question, ma non sono riuscito a capire perché questo accada. A mio parere, lo doSth("foo", 2L) è più specifico della firma doSth(String string, long l, Object... obj) e dovrebbe consentire al compilatore di arrivare anche a questa conclusione.

+0

Evidentemente i primitivi possono anche essere oggetti? –

+0

@blahfunk, sì, potrebbero essere impacchettati – Andrew

+0

L'unica spiegazione che viene in mente è [Autoboxing] (https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html), ma questo dovrebbe essere un passo di conversione "più lontano" rispetto alla versione primitiva del metodo. – Turing85

risposta

5

In questo caso, l'auto-boxing sta causando dolore. Ironicamente, prima che tu abbia ragione, la versione "lunga" sarebbe stata facilmente selezionata.

Fondamentalmente il compilatore sa che può creare un Long dal tuo valore che, ovviamente, è un Oggetto. Quindi è ancora confuso in quanto potrebbe essere utilizzata la versione lunga o lunga. Uno è "migliore" dell'altro? Forse, ma è una linea piuttosto sottile.

+1

Bene, [fase 1] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15. html # jls-15.12.2) nel JLS specifica esplicitamente * esegue la risoluzione di sovraccarico senza consentire la conversione boxing o unboxing *. In questa fase, la funzione di autoboxing non viene eseguita. Sembra che 'doSth (String str, long l, Object ... objects)' debba essere scelto in quella fase. Mi sto perdendo qualcosa? – Tunaki

+0

Questo è divertente. Perché ciò non causa il caos, quando c'è un solo parametro, ad esempio 'doSth (long l)' e 'doSth (Object o)'? – Turing85

+3

@Tunaki Le fasi 1 e 2 escludono anche i metodi di arbitraggio variabile, quindi nessuno dei metodi di OP viene considerato fino alla fase 3. Stranamente, 'doSth (" foo ", 2L, null)' verrà compilato a causa di ciò che la nota in corsivo sotto il primo punto (nel tuo link) afferma. – Radiodef

1

In questo stato, posso solo riportare la mia osservazione, non l'argomentazione esatta su come si comporta Java, come fa.

Innanzitutto, cambiando i metodi per

void doSth(long l) {...} 
void doSth(Object o) {...} 

si libera del problema, cioè doSth(2L); produce il risultato previsto.

Andando un passo ulteriore, modificando il parametro metodo per varargs

void doSth(long... ls) {...} 
void doSth(Object... os) {...} 

insieme con la chiamata doSth(2l); produce lo stesso errore di compilazione come riportato da OP.

Il mio suggerimento in questa fase è che l'encapusalting del parametro in una matrice, insieme con Autoboxing provoca il caos. La mia conoscenza del JLS non è abbastanza solida da spiegarlo correttamente.