在此代码中,
package com.example;
interface CollectorIF<T> {
// @SafeVarargs // Error: @SafeVarargs annotation cannot be applied to non-final instance method addAll
void addAll(T... values);
}
class Collector<T> implements CollectorIF<T> {
@SafeVarargs
public final void addAll(T... values) {
}
}
class Component<T> {
public void compute(T value) {
Collector<T> col1 = new Collector<>();
col1.addAll(value); // No warning
CollectorIF<T> col2 = new Collector<>();
col2.addAll(value); // Type safety: A generic array of T is created for a varargs parameter
}
}
由于Type safety: A generic array of T is created for a varargs parameter
注释,使用Collector<T>
引用时未发生@SafeVarargs
警告。
但是,通过CollectorIF<T>
界面访问方法时会出现警告 。在接口方法上,@SafeVarargs
无效(这很明显,因为编译器无法对方法体中参数的使用情况进行任何检查)。
通过界面访问方法时如何避免警告?
答案 0 :(得分:9)
没有办法避免这种警告,因为无法安全地定义具有通用varargs方法的接口。
CollectiorIF
的另一个实现可能会滥用该参数,导致CollectorIF.addAll()
的任何调用者容易受到奇怪的运行时行为的攻击。您可以假设接口和非最终方法应该允许@SafeVarargs
(并要求实现/覆盖方法同样注释),但是目前Java开发人员有意识地决定不支持这种模式。
JLS提供了更多背景知识:
在发生方法重写的地方,注释不可用。注释继承仅适用于类(而不是方法,接口或构造函数),因此不能通过类或通过接口中的实例方法传递@ SafeVarargs样式的注释。
与此同时,你有两个选择;忽略警告或重构您的API。
重构您的API实际上可能正是您想要的,因为通用的vararg方法只应用作实际的,通用的通用实现的桥梁。而不是将其定义为接口的一部分(因此需要所有实现实现它),而是将其作为静态实用程序方法提供,从而使接口的API更小,同时仍然为调用者提供使用varargs的灵活性。从Java 8开始,甚至可以在界面中定义实用方法。
@SafeVarargs
public static <T> void addAll(CollectorIF<T> collector, T... values) {
collector.addAll(Arrays.asList(values));
}
然后,您的界面应该定义一个addAll(Iterable<T> values)
方法,让实现者完全避开泛型varargs的狡猾世界。