Java 通过varargs参数可能导致堆污染
我理解Java 7在使用泛型类型的varargs时会出现这种情况 但我的问题是 Eclipse说“它的使用可能会污染堆”的确切含义是什么 及Java 通过varargs参数可能导致堆污染,java,eclipse,generics,variadic-functions,Java,Eclipse,Generics,Variadic Functions,我理解Java 7在使用泛型类型的varargs时会出现这种情况 但我的问题是 Eclipse说“它的使用可能会污染堆”的确切含义是什么 及 新的@SafeVarargs注释如何防止这种情况发生?@SafeVarargs并不能防止这种情况发生,但它要求编译器在编译使用它的代码时更加严格 更详细地解释了这一点 堆污染是指当您在通用接口上执行操作时得到一个ClassCastException,并且它包含声明之外的另一种类型。堆污染是一个技术术语。它引用的类型不是所指向对象的超类型的引用 List&l
新的
@SafeVarargs
注释如何防止这种情况发生?@SafeVarargs
并不能防止这种情况发生,但它要求编译器在编译使用它的代码时更加严格
更详细地解释了这一点
堆污染是指当您在通用接口上执行操作时得到一个
ClassCastException
,并且它包含声明之外的另一种类型。堆污染是一个技术术语。它引用的类型不是所指向对象的超类型的引用
List<A> listOfAs = new ArrayList<>();
List<B> listOfBs = (List<B>)(Object)listOfAs; // points to a list of As
@SafeVarargs
根本无法阻止这一点。然而,有些方法可以证明不会污染堆,编译器无法证明。以前,此类API的调用者会收到恼人的警告,这些警告完全没有意义,但必须在每个调用站点进行抑制。现在API作者可以在声明站点对其进行一次抑制
但是,如果该方法实际上不安全,用户将不再收到警告。使用varargs时,可能会创建一个
对象[]
来保存参数
由于escape分析,JIT可以优化此阵列创建。(我发现这是为数不多的一次)它不一定会被优化,但我不会担心它,除非你在内存分析器中看到它的问题
AFAIK@SafeVarargs
禁止编译器发出警告,并且不会更改JIT的行为方式。当您声明
publicstaticvoidfoo(List…bar)
编译器将其转换为
publicstaticvoidfoo(列表[]条)
publicstaticvoidfoo(列表[]条)
这样一来,您可能会错误地将不正确的值分配到列表中,并且编译器不会触发任何错误。例如,如果T
是字符串
,则以下代码将编译无误,但在运行时将失败:
// First, strip away the array type (arrays allow this kind of upcasting)
Object[] objectArray = bar;
// Next, insert an element with an incorrect type into the array
objectArray[0] = Arrays.asList(new Integer(42));
// Finally, try accessing the original array. A runtime error will occur
// (ClassCastException due to a casting from Integer to String)
T firstElement = bar[0].get(0);
如果您检查了该方法以确保其不包含此类漏洞,则可以使用@SafeVarargs
对其进行注释以抑制警告。对于接口,请使用@SuppressWarnings(“未选中”)
如果您收到此错误消息:
Varargs方法可能会由于不可恢复的Varargs参数而导致堆污染
如果您确信您的使用是安全的,那么您应该使用@SuppressWarnings(“varargs”)
。有关第二种错误的详细解释,请参见和
参考资料: