2012-10-14 19 views
20

Il seguente codice non viene compilato.Vararg in overloading dei metodi in Java

package varargspkg; 

public class Main { 

    public static void test(int... i) { 
     for (int t = 0; t < i.length; t++) { 
      System.out.println(i[t]); 
     } 

     System.out.println("int"); 
    } 

    public static void test(float... f) { 
     for (int t = 0; t < f.length; t++) { 
      System.out.println(f[t]); 
     } 

     System.out.println("float"); 
    } 

    public static void main(String[] args) { 
     test(1, 2); //Compilation error here quoted as follows. 
    } 
} 

Viene generato un errore in fase di compilazione.

riferimento al test è ambigua, sia metodo di prova (int ...) in varargspkg.Main e metodo di prova (float ...) in varargspkg.Main partita

sembra essere evidenti perché i valori dei parametri del metodo chiamano test(1, 2); può essere promosso a int nonché float

Se uno o entrambi i parametri vengono suffisso F o f, compila.


Se tuttavia, rappresentano i parametri di ricezione nella firma metodo di rispettivi tipi involucro come segue

public static void test(Integer... i) { 
    System.out.println("Integer" + Arrays.asList(i)); 
} 

public static void test(Float... f) { 
    System.out.println("Float" + Arrays.asList(f)); 
} 

quindi la chiamata al metodo test(1, 2); non emette alcun errore di compilazione. Il metodo da invocare in questo caso è quello che accetta un parametro varargs Integer (il primo nello snippet precedente).

Perché è in questo caso l'errore come nel primo caso non segnalato? Sembra che sia stata applicata la promozione automatica del tipo di auto-boxing e quella automatica qui. Il box automatico viene applicato per primo in modo che l'errore sia risolto?

la documentazione Oracle dice,

In generale, non si dovrebbe sovraccaricare un metodo varargs, o sarà difficile per i programmatori di capire quale sovraccarico ottiene chiamato.

L'ultima frase in questo link. È tuttavia nell'interesse di una migliore comprensione delle vararg.

Anche per aggiungere codice sotto compila bene.

public class OverLoading { 

    public static void main(String[] args) { 
     load(1); 
    } 

    public static void load(int i) { 
     System.out.println("int"); 
    } 

    public static void load(float i) { 
     System.out.println("float"); 
    } 
} 

EDIT:

che segue è la snap shot che indica l'errore di compilazione. Ho creato una nuova applicazione, quindi il nome del pacchetto è diverso.

enter image description here

sto usando JDK 6.

+3

Il codice originale funziona correttamente per me.L'output era int – techfoobar

+0

@techfoobar - Il codice nel primo frammento non viene compilato per me (con jdk 6, NetBeans 6.9.1). Produce l'errore di compilazione come specificato. Ti sta davvero compilando? – Tiny

+0

Buona domanda. Vorrei aggiungere che viene risolto quando sovrascriviamo il singolo parametro (int) e (float). Sento odore di bug qui. –

risposta

9

È possibile Widen o Box ma non è possibile fare entrambe le cose, se non si è boxing and widening-Object (Valore int in numero intero (Boxe) e poi Integer a Object (allargamento) è legale, dal momento che ogni classe è una sottoclasse di Object, quindi è possibile per Integer da passare al parametro Object)

Allo stesso modo un int per Number è anche legale (int -> intero -> Number) Dal numero è la classe eccellente di Integer è possibile.

Vediamo questo nel tuo esempio: -

public static void test(Integer...i) 

public static void test(Float...f) 

Ci sono alcune regole che sono seguite quando si seleziona il metodo da selezionare, quando la boxe, ampliando e Var-args sono combinati in sovraccarico: -

  1. Primitive allargamento utilizza l'argomento smallest metodo possibile
  2. tipo
  3. involucro non può essere allargato ad un altro tipo Wrapper
  4. 012.
  5. È possibile eseguire il box da int a numero intero e ingrandirlo a oggetto ma no a lungo
  6. battiti di ampliamento boxing, battiti di boxe var.
  7. È possibile dialogo e quindi Widen (An int può diventare Object via Integer)
  8. Non si può allargare e poi Box (An int non può diventare Long)
  9. Non è possibile combinare Var-args, sia con l'ampliamento o la boxe

Quindi, sulla base dei dati regole di cui sopra: -

Quando si passa due interi a funzioni di cui sopra,

  • base alla regola 3, dovrà essere il primo Widened e poi Boxed di inserirsi in un Long, che è secondo illegale di governare 5 (Non si può allargare e poi Box).
  • Quindi, è in box per archiviare in variabili Integer var-args.

Ma nel primo caso, in cui si dispone di metodi con var-args dei tipi primitivi: -

public static void test(int...i) 
public static void test(float...f) 

Poi test(1, 2) possono richiamare entrambi i metodi (Dal momento che nessuno dei due è più adatto per rule 1 a pagamento): -

  • Nel primo caso sarà var-args
  • Nel secondo caso, sarà Widen ING e poi Var-args (che è consentito)

Ora, quando si dispone di metodi con esattamente un int e un flost: -

public static void test(int i) 
public static void test(float f) 

quel momento in poi invocare usando test(1), regola 1 è seguito, e il più piccolo allargamento possibile (es lo int in cui non è necessario alcun allargamento) viene scelto. Quindi il primo metodo sarà invocato.

Per ulteriori informazioni, è possibile consultare JLS - Method Invocation Conversion

+0

@Tiny. Penso che dovresti dare un'occhiata a quello che ho spiegato. Penso che sarà chiaro per te. :) –

+0

Rohit, per essere precisi, non esiste una cosa come * inscatolare un 'int' su un'istanza di' Object' *. Quello che succede, in realtà, quando si passa un 'int' a una funzione che accetta un' Object' è che il 'int' è autoboxed a un'istanza di' Integer', che può essere visto come un 'Object' poiché ogni classe eredita dall'oggetto. Per verificarlo, 'classe x {booleano b (oggetto o) {return o.getClass() == Object.class;} void main (String ... args) {System.out.println (b (1)); }} 'stamperà false. Ovviamente, cambiando in 'o.getClass() instanceof Object' verrà stampato true. –

+0

(e questo è il motivo per cui è anche legale passare un 'int' a un metodo che prende un'istanza di' Number' come parametro - 'Integer' eredita da' Number') –

2

In Java, 1 è come voi rappresentate un int. Può essere auto-inscatolato a un'istanza di Integer o promosso a float e questo spiega perché il compilatore non può decidere il metodo che deve chiamare. Ma non sarà mai auto-boxato a Long o Float (o qualsiasi altro tipo).

D'altra parte, se si scrive 1F, è la rappresentazione di un float, che può essere auto-boxed ad un Float (e, nello stesso spirito, non potrà mai essere auto-boxed ad un Integer o niente altro).

2

In Java 6, il problema si trova al momento del instantiation dei generici prima di trovare quale metodo è disponibile per chiamare.

When you write 1,2 
    -> it can be be both int[] or float[] and hence the issue being complained. 

When you write 1,2F 
    -> it can be be only float[] and hence the NO issue being complained. 

Stessa cosa con altre due possibilità cioè

When you write 1F,2 
    -> it can be be only float[] and hence the NO issue being complained. 

When you write 1F,2F 
    -> it can be be only float[] and hence the NO issue being complained. 

D'altra parte, quando si utilizza int o float, non v'è alcun tipo di un'istanza variabile. Quando si utilizza 1, tenta di trovare il metodo con int come argomento per primo, in caso contrario, promuove il tipo e identifica il metodo con float. Se sono disponibili entrambi i metodi, verrà utilizzato prima uno con lo int.

Problema di ambiguità non disponibile in Java 7 in quanto ha una migliore gestione del controllo e della promozione del tipo di dati.

+1

Con la tua logica dovrebbe anche dare un errore quando sovrascriviamo il singolo parametro int e float. Ma non sta dando alcun errore. overLoading di classe pubblica { \t public static void main (String [] args) { \t \t carico (1); \t} \t \t carico public static void (int i) { \t \t System.out.println ("Int"); \t} \t \t carico static void (float i) { \t \t System.out.println ("float"); \t} } –

+0

Quando si esegue l'override anche del singolo parametro, ad es. '1, 2F', essendo un parametro come float rigido, l'unico metodo applicabile è' test (float ..) 'e non' main (int ..) '. Che come non c'è ambiguità e quindi nessun problema. –

+0

Quindi dici che l'output dell'esempio (ora aggiunto alla domanda) verrà visualizzato float? –

2

Perché in questo caso l'errore come nel primo caso non ha riportato? Sembra che sia stata applicata la promozione automatica del tipo di auto-boxing e quella automatica qui. Prima viene applicato il box automatico, l'errore è stato risolto?

Solo un parere: in caso di vararg, la JVM deve effettivamente creare una serie di argomenti. Nel caso di Integer e Float, è ovvio quale tipo di array dovrebbe creare. Quindi, probabilmente potrebbe essere la ragione per nessun errore di ambiguità.

Tuttavia, è un po 'di confusione, perché non è possibile creare un array di numeri interi, quando per impostazione predefinita 1, 3 sono interi.

Sembra che questo sia stato discusso qui in SO in passato bug with varargs and overloading? ed è infatti a bug, secondo la discussione.

Problemi correlati