Реализация универсального метода с varargs
В моем коде удобно использовать 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) {...}
}
Когда я пишу это, Eclipse показывает предупреждение:
Методы Varargs должны переопределяться или переопределяться другими varargs в отличие от MyCodec.encode(байт...) и Codec.encode(байт [])
Должен ли я просто игнорировать предупреждение, или это вызовет некоторые непредвиденные проблемы?
Ответы
Ответ 1
Это специальное предупреждение для Eclipse. Он не имеет ничего общего с дженериками и может быть воспроизведен с помощью этого примера:
class A {
m(int[] ints) { }
}
class B extends A {
@Override
m(int... ints) { }
}
Как указывают другие ответы, varargs - это просто функция времени компиляции, и во время выполнения нет никакой разницы. Я попытался найти конкретные аргументы за предупреждением, но ничего не мог поделать. Вероятно, он считал, что неправильная практика чередует переопределения методов между varargs и non-varargs, потому что это запутанно и произвольно. Но это в целом - ваш пример использования кажется более разумным, если вызывающие абоненты всегда будут использовать статически типизированный MyCodec
вместо кодирования для взаимодействия с Codec<byte[], char[]>
.
К сожалению, нет способа подавить это предупреждение - даже @SuppressWarnings("all")
не даст результата. Что печально, учитывая, насколько неясным является предупреждение. Здесь древний разговор по этому же вопросу: http://echelog.com/logs/browse/eclipse/1196982000 (прокрутите до 20:45:02) - доказав, что это бит, люди задолго до вас. Кажется, что ошибка Eclipse не может быть подавлена.
Ответ 2
Я написал два тестовых файла. Здесь первое:
public class Test {
public static void main(String... args) {
System.out.println(java.util.Arrays.toString(args));
}
}
А вот второе:
public class Test {
public static void main(String[] args) {
System.out.println(java.util.Arrays.toString(args));
}
}
(Единственное различие между этими двумя файлами - String[] args
vs String... args
.)
Затем я запустил javap -c
в каждом файле, чтобы увидеть разборку. Содержимое метода main
было идентичным:
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
Единственным отличием был заголовок метода, который был просто сигнатурой метода для каждого метода:
-
public static void main(java.lang.String[]);
-
public static void main(java.lang.String...);
С учетом этого я бы сказал, что это безопасное предположение, что ничего плохого не произойдет.
Ответ 3
В соответствии с байт-кодом нет проблем.
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
Если вы делаете вызов с использованием одной ссылки интерфейса, метод с флагом ACC_BRIDGE
check (checkcast
), если тип аргумента такой же, как определено в параметре типа (java.lang.ClassCastException
иначе, но никогда не произойдет, если вы всегда предоставляете , затем запустите реализацию метода.
В другой руке, если вы скомпилируете это с помощью javac, ни одно предупреждение не отображается.