1)Internet和StackOverflow上有许多有关泛型和varargs特定问题的示例。基本上,这是当您拥有数量可变的类型参数类型的参数时:
<T> void foo(T... args);
在Java中,varargs是一种语法糖,在编译时会进行简单的“重写”:类型X...为varargs的参数将转换为类型为的参数X[];每次调用此varargs方法时,编译器都会收集varargs参数中包含的所有“变量参数”,并像创建一个数组new X[] { ...(arguments go here)... }。
当varargs类型为时,此方法效果很好String...。当它是类型变量(如)时T...,也可以在T已知为该调用的具体类型时使用。例如,如果上述方法是类的一部分Foo<T>,并且您有一个Foo<String>引用,则可以调用foo它,因为我们知道代码T就String在那一点上。
但是,当of的“值” T是另一个类型参数时,它将不起作用。在Java中,无法创建类型参数组件类型(new T[] { ... })的数组。所以Java改为使用new Object[] { ... }(这Object是的上限T;如果上限不同,则应使用而不是Object),然后向您发出编译器警告。
那么创建new Object[]而不是new T[]什么有什么问题呢?好吧,Java中的数组在运行时知道其组件类型。因此,传递的数组对象在运行时将具有错误的组件类型。
对于varargs的最常见用法,仅是遍历元素,这没有问题(您不必关心数组的运行时类型),因此这是安全的:
@SafeVarargs
final <T> void foo(T... args) {
    for (T x : args) {
        // do stuff with x
    }
}
但是,对于任何依赖于所传递数组的运行时组件类型的事物,这都是不安全的。这是不安全并崩溃的简单示例:
class UnSafeVarargs
{
  static <T> T[] asArray(T... args) {
    return args;
  }
  static <T> T[] arrayOfTwo(T a, T b) {
    return asArray(a, b);
  }
  public static void main(String[] args) {
    String[] bar = arrayOfTwo("hi", "mom");
  }
}
这里的问题是,我们依靠的类型args是T[]为了回击T[]。但是实际上,运行时参数的类型不是的实例T[]。
3)如果您的方法的参数类型 T...类型参数(其中T是任何类型参数),则:
- 安全:如果您的方法仅取决于以下事实,即数组的元素是以下元素的实例: T
- 不安全:如果取决于数组是以下对象的实例的事实 T[]
依赖于数组的运行时类型的事情包括:将其作为类型返回T[],将其作为参数传递给type参数T[],使用获取数组类型.getClass(),将其传递给依赖于数组的运行时类型的方法,例如List.toArray()和Arrays.copyOf()等
2)我上面提到的区别太复杂了,以至于不能轻易自动区分。