使用 varargs 实现泛型方法

2022-09-04 21:11:59

在我的代码中,当类型是数组时,在实现泛型方法时使用 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(byte[])

我应该忽略警告,还是这会导致一些不可预见的问题?


答案 1

这是特定于 Eclipse 的警告。它与泛型无关,可以通过此示例复制:

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

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

正如其他答案所指出的那样,varargs纯粹是一个编译时功能,在运行时没有区别。我试图搜索警告背后的具体原因,但无法找到任何东西。在 varargs 和非 varargs 之间交替使用方法覆盖可能被认为是不好的做法,因为它令人困惑且具有任意性。但这是一般的 - 只要调用方总是使用静态类型而不是编码来与.MyCodecCodec<byte[], char[]>

不幸的是,没有办法抑制这个警告 - 甚至不会让它屈服。考虑到警告的晦涩程度,这是不幸的。这里有一个关于同一问题的古老对话:http://echelog.com/logs/browse/eclipse/1196982000(滚动到20:45:02) - 证明它比你早得多。似乎是一个 Eclipse bug,无法抑制它。@SuppressWarnings("all")


答案 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));
    }
}

(这两个文件之间的唯一区别是 vs .)String[] argsString... args

然后,我在每个文件上运行以查看反汇编。该方法的内容是相同的:javap -cmain

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...);

考虑到这一点,我会说这是一个安全的假设,即不会发生任何不好的事情。