在我的代码中,当类型是数组时,在实现泛型方法时使用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(byte ...)和 Codec.encode(字节[])
我应该忽略这个警告,还是会导致一些不可预见的问题呢?
答案 0 :(得分:5)
这是一个特定于Eclipse的警告。它与generics无关,可以通过这个例子重现:
class A {
m(int[] ints) { }
}
class B extends A {
@Override
m(int... ints) { }
}
正如其他答案所指出的,varargs纯粹是一个编译时功能,在运行时没有区别。我试图寻找警告背后的具体原因,但无法改变任何事情。可能在varargs和非varargs之间交替方法覆盖被认为是不好的做法,因为它令人困惑和随意。但这通常是 - 只要呼叫者总是使用静态类型MyCodec
而不是编码与Codec<byte[], char[]>
接口,您的用例似乎更合理
不幸的是,没有办法压制这个警告 - 即使@SuppressWarnings("all")
也不会让它屈服。考虑到警告是多么模糊,这是不幸的。以下是关于同一问题的古老对话:http://echelog.com/logs/browse/eclipse/1196982000(滚动到20:45:02) - 证明在你之前很久就有点人。看起来像是一个无法抑制的Eclipse bug。
答案 1 :(得分:4)
我写了两个测试文件。这是第一个:
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
与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...);
考虑到这一点,我会说这是一个安全的假设,没有什么不好的事情会发生。
答案 2 :(得分:1)
根据字节码,没问题。
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
的方法检查(checkcast
),如果参数的类型与type参数中定义的相同( java.lang.ClassCastException
否则,但如果你总是提供type parameter,则永远不会发生,然后运行方法实现。
另一方面,如果使用javac编译它,则不会显示任何警告。