2013-06-06 11 views
11

w moim kodu, wydaje się wygodny w użyciu varargs podczas wdrażania metody rodzajowe, gdy typ jest tablicą:wykonawczych metoda rodzajowa z 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) {...} 
} 

Kiedy piszę te słowa, Eclipse pokazuje ostrzeżenie:

metody

varargs należy tylko zastępują lub mogą być zastąpione przez inne varargs metody przeciwieństwie MyCodec.encode (bajt ...) i Codec.encode bajt ([])

Czy powinienem zignorować ostrzeżenie, czy może spowoduje to nieprzewidziane problemy?

+0

Co to jest szybka naprawa Eclipse? Czy istnieje 'SuppressWarnings (" varargs ")' lub podobny? (po prostu ciekawy) – wchargin

+0

Czy to możliwe, że ostrzeżenie jest na wypadek, gdyby pewnego dnia podpisy metod nie były uważane za równoważne? Odd ... –

Odpowiedz

5

To jest ostrzeżenie specyficzne dla środowiska Eclipse. To nie ma nic wspólnego z rodzajowych konkretnie i mogą być odtwarzane z tego przykładu:

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

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

jak inne odpowiedzi podkreślić, varargs są wyłącznie cechą czasu kompilacji i nie ma różnicy w czasie wykonywania. Próbowałem znaleźć konkretne uzasadnienie ostrzeżenia, ale nie mogłem niczego zmienić. Prawdopodobnie jest uważane za złą praktykę zastępowania nadpisań metod między varargs i non-varargs, ponieważ jest to mylące i arbitralne.Ale to jest ogólnie - Twój przypadek użycia wydaje się bardziej uzasadniony, o ile osoby dzwoniące będą zawsze używać statycznie wpisanego MyCodec zamiast kodowania do interfejsu z Codec<byte[], char[]>.

Niestety, nie ma sposobu, aby ukryć to ostrzeżenie - nawet @SuppressWarnings("all") nie sprawi, że się ustąpi. Co jest niefortunne, biorąc pod uwagę, jak niejasne jest ostrzeżenie. Oto starodawna rozmowa na ten sam temat: http://echelog.com/logs/browse/eclipse/1196982000 (przewiń do 20:45:02) - udowadniając, że to trochę ludzie na długo przed tobą. Wygląda jak błąd Eclipse, którego nie można wyłączyć.

4

Napisałem dwa pliki testowe. Oto pierwszy:

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

A oto drugi:

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

(. Jedyna różnica pomiędzy tymi dwoma plikami jest String[] args vs String... args)

Potem wpadłem javap -c na każdym pliku aby zobaczyć demontaż. Zawartość metody main były identyczne:

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  

Jedyna różnica polegała na nagłówek metoda, która była po prostu podpis metoda każdej metody:

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

Mając to na uwadze, powiedziałbym, że jest to bezpieczne założenie, że nic złego się nie stanie.

+0

Dniewca, proszę wyjaśnić? – wchargin

+6

Nie jestem downvoter, ale tylko dlatego, że oba przykłady wkompilować w ten sam kod bajtowy, nie oznacza, że ​​ostrzeżenie nie ma znaczenia. Generyczny i nietypowy kod kompiluje się na przykład w ten sam kod bajtowy. –

1

Zgodnie z kod bajtowy, nie ma problemu.

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 

Jeśli nawiązać połączenie przy użyciu jedno odwołanie interfejsu, metodę z czekiem flag ACC_BRIDGE (checkcast) czy typ argumentu jest taka sama jak jest zdefiniowany w parametrze typu (java.lang.ClassCastException inaczej, ale nigdy się nie stanie, jeśli zawsze zapewniasz type parameter), a następnie uruchom implementację metody.

W innym przypadku, jeśli skompilujesz to przy pomocy javac, żadne ostrzeżenie nie zostanie wyświetlone.