public <T> void doSomething(A a, B b, T... manyTs) {
// Your code here
}
将其更改为:
public <T> void doSomething(A a, B b, T... manyTs) {
doSomething(a, b, Arrays.asList(manyTs));
}
private <T> void doSomething(A a, B b, List<T> manyTs) {
// Your code here
}
3条答案
按热度按时间rqmkfv5c1#
1)在Internet和StackOverflow上有很多关于泛型和varargs的例子,基本上,这是当你有一个类型参数类型的变量数量时的情况:
在Java中,varargs是一种语法糖,在编译时会经历简单的“重写”:将类型
X...
的varargs参数转换为类型X[]
的参数;每次调用这个varargs方法时,编译器都会收集varargs参数中的所有“变量参数”,并创建一个类似于new X[] { ...(arguments go here)... }
的数组。当varargs类型是
String...
这样的具体类型时,这很有效。当它是T...
这样的类型变量时,当T
已知是该调用的具体类型时,它也有效。例如,如果上面的方法是Foo<T>
类的一部分,并且您有一个Foo<String>
引用,那么在它上面调用foo
是可以的,因为我们知道在代码的那个点上T
是String
。但是,当
T
的“值”是另一个类型参数时,它就不起作用了,在Java中,不可能创建一个类型参数组件类型(new T[] { ... }
)的数组,所以Java改为使用new Object[] { ... }
(这里Object
是T
的上界;如果上限不同,则应该是that而不是Object
),然后向您提供编译器警告。那么创建
new Object[]
而不是new T[]
或其他什么东西有什么问题呢?Java中的数组在运行时知道它们的组件类型,因此,传递的数组对象在运行时会有错误的组件类型。对于varargs最常见的用法,简单地迭代元素,这是没有问题的(你不关心数组的运行时类型),所以这是安全的:
但是,对于依赖于传递数组的运行时组件类型的任何东西,它都将是不安全的。下面是一个不安全和崩溃的简单示例:
这里的问题是,我们依赖于
args
的类型是T[]
,以便将其返回为T[]
,但实际上参数在运行时的类型不是T[]
的示例。3)如果方法具有
T...
类型的参数(其中T是任何类型参数),则:T
的示例这一事实T[]
的示例这一事实取决于数组运行时类型的内容包括:以
T[]
类型返回,将其作为实参传递给T[]
类型的参数,使用.getClass()
获取数组类型,将其传递给依赖于数组的运行时类型的方法,如List.toArray()
和Arrays.copyOf()
等。2)我上面提到的区别太复杂了,很难自动区分。
vfh0ocws2#
要获得最佳实践,请考虑以下内容。
如果你有这个:
将其更改为:
我发现我通常只添加varargs来使调用者更方便。对于我的内部实现来说,使用
List<>
几乎总是更方便。因此,为了在Arrays.asList()
上搭载并确保没有办法引入堆污染,这就是我所做的。我知道这只回答了你的第三个问题。newacct已经为上面的第一个和第二个问题给出了很好的答案,我没有足够的声誉来留下评论。:P
eyh26e7m3#
@SafeVarargs用于指示方法不会导致堆污染。
堆污染是当我们在泛型数组中混合不同的参数化类型时。
例如:
如您所见,如果我们不使用类型进行猜测,这样的实现很容易导致
ClassCastException
。