1)在Internet和StackOverflow上有很多关于泛型和varargs特定问题的例子。基本上,这是当你有一个类型参数类型的可变数量的参数时:
<T> void foo(T... args);
在Java中,varargs是一种语法糖,在编译时经历简单的“重写”:类型的varargs参数被转换为类型的参数;并且每次调用此 varargs 方法时,编译器都会收集 varargs 参数中的所有“变量参数”,并创建一个类似于 的数组。X...
X[]
new X[] { ...(arguments go here)... }
当 varargs 类型是具体的,如 .当它是一个类型变量时,当已知是该调用的具体类型时,它也可以工作。例如,如果上面的方法是类的一部分,并且您有一个引用,那么调用它就可以了,因为我们知道在代码中的那个点。String...
T...
T
Foo<T>
Foo<String>
foo
T
String
但是,当 的“值”是另一个类型参数时,它不起作用。在 Java 中,不可能创建类型参数组件类型 () 的数组。所以Java改用(这里是上限;如果上限是不同的东西,那就是那个而不是),然后给你一个编译器警告。T
new T[] { ... }
new Object[] { ... }
Object
T
Object
那么,创造而不是什么的有什么问题呢?好吧,Java中的数组在运行时知道它们的组件类型。因此,传递的数组对象在运行时将具有错误的组件类型。new Object[]
new T[]
对于可能是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[]
T[]
.getClass()
List.toArray()
Arrays.copyOf()
2)我上面提到的区别太复杂了,不容易自动区分。