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)我上面提到的区别太复杂了,以至于不能轻易自动区分。