2013-06-06 20 views
11

nel mio codice, appare conveniente usare varargs nell'attuazione un metodo generico quando il tipo è un array:attuazione di un metodo generico con varargs

public interface Codec<D,E> { 
    E encode(D decoded); 
    D decode(E encoded); 
} 

public class MyCodec implements Codec<byte[], char[]> { 
    @Override char[] encode(byte... decoded) {...} 
    @Override byte[] decode(char... encoded) {...} 
} 

Quando scrivo questo, Eclipse mostra un avvertimento:

metodi

varargs solo dovrebbe ignorare o essere sovrascritta da altri varargs metodi differenza MyCodec.encode (byte ...) e Codec.encode (byte [])

Devo semplicemente ignorare l'avviso, o questo causerà alcuni problemi imprevisti?

+0

Qual è la correzione rapida di Eclipse? C'è un 'SuppressWarnings (" varargs ")' o simile? (solo curioso) – wchargin

+0

Potrebbe essere che l'avviso è nel caso in cui le firme del metodo non sono considerate equivalenti? Odd ... –

risposta

5

Questo è un avviso specifico di Eclipse. Non ha nulla a che fare con i generici in modo specifico e può essere riprodotto con questo esempio:

class A { 
    m(int[] ints) { } 
} 

class B extends A { 
    @Override 
    m(int... ints) { } 
} 

Come le altre risposte sottolineano, varargs sono puramente una caratteristica in fase di compilazione e non c'è alcuna differenza in fase di esecuzione. Ho provato a cercare il ragionamento specifico dietro l'avvertimento, ma non ho potuto attivare nulla. Probabilmente è considerata una cattiva pratica alternare l'override dei metodi tra vararg e non-vararg perché è confusionario e arbitrario.Ma questo è in generale - il tuo caso d'uso sembra più ragionevole a patto che i chiamanti usino sempre uno MyCodec con codice statico invece di codificare per interfacciare con uno Codec<byte[], char[]>.

Sfortunatamente non c'è modo di sopprimere questo avvertimento - anche @SuppressWarnings("all") non lo farà cedere. Il che è spiacevole considerando quanto sia oscuro un avvertimento. Ecco un'antica conversazione su questo stesso numero: http://echelog.com/logs/browse/eclipse/1196982000 (scorrere fino alle 20:45:02) - provando che sono un po 'le persone molto prima di te. Sembra un bug di Eclipse che non può essere soppresso.

4

Ho scritto due file di test. Ecco la prima:

public class Test { 
    public static void main(String... args) { 
     System.out.println(java.util.Arrays.toString(args)); 
    } 
} 

Ed ecco il secondo:

public class Test { 
    public static void main(String[] args) { 
     System.out.println(java.util.Arrays.toString(args)); 
    } 
} 

(. L'unica differenza tra questi due file è il String[] args vs String... args)

Poi, mi sono imbattuto javap -c su ogni file per vedere lo smontaggio. Il contenuto del metodo main erano identici:

Code: 
    0: getstatic  #2     // Field java/lang/System.out:Ljava/io/PrintStream; 
    3: aload_0  
    4: invokestatic #3     // Method java/util/Arrays.toString:([Ljava/lang/Object;)Ljava/lang/String; 
    7: invokevirtual #4     // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    10: return  

L'unica differenza è il metodo di testa, che era semplicemente la firma del metodo di ciascun metodo:

  • public static void main(java.lang.String[]);
  • public static void main(java.lang.String...);

Con questo in mente, direi che è un presupposto sicuro che non accadrà nulla di male.

+0

Downvoter, per favore spieghi? – wchargin

+6

Non sono il downvoter, ma solo perché entrambi gli esempi vengono compilati nello stesso bytecode non significa che l'avviso non abbia significato. Ad esempio, il codice generico e non generico viene compilato nello stesso byte-code. –

1

Secondo il codice bytecode, nessun problema.

public byte[] encode(char...); 
    flags: ACC_PUBLIC, ACC_VARARGS 

    LineNumberTable: 
    line 4: 0 
    LocalVariableTable: 
    Start Length Slot Name Signature 
      0  2  0 this LMyEncoder; 
      0  2  1 args [C   // char[] 
    Code: 
    stack=1, locals=2, args_size=2 
     0: aconst_null 
     1: areturn        // return null; 
    LineNumberTable: 
     line 4: 0 
    LocalVariableTable: 
     Start Length Slot Name Signature 
      0  2  0 this LMyEncoder; 
      0  2  1 args [C 

public java.lang.Object encode(java.lang.Object); 
    flags: ACC_PUBLIC, ACC_BRIDGE, ACC_VARARGS, ACC_SYNTHETIC 

    LineNumberTable: 
    line 1: 0 
    LocalVariableTable: 
    Start Length Slot Name Signature 
    Code: 
    stack=2, locals=2, args_size=2 
     0: aload_0  
     1: aload_1  
     2: checkcast  #27   // class "[C"   -> char[] 
     5: invokevirtual #28   // Method encode:([C)[B -> return byte[] 
     8: areturn  
    LineNumberTable: 
     line 1: 0 
    LocalVariableTable: 
     Start Length Slot Name Signature 

Se si effettua una chiamata utilizzando uno riferimento dell'interfaccia, il metodo con il controllo bandiera ACC_BRIDGE (checkcast) se il tipo di argomento è lo stesso come è definito nel parametro tipo (java.lang.ClassCastException altrimenti, ma non succederà mai se fornisci sempre il type parameter), quindi esegui l'implementazione del metodo.

In un'altra mano, se si compila questo con javac, non viene visualizzato alcun avviso.

Problemi correlati