我了解当在使用泛型类型和可变参数(varargs)时,Java 7会出现这种情况;
但我的问题是..
当Eclipse说“它的使用可能会污染堆(heap)”时,它到底是什么意思?
还有,
新的@SafeVarargs
注解如何防止这种情况发生?
我了解当在使用泛型类型和可变参数(varargs)时,Java 7会出现这种情况;
但我的问题是..
当Eclipse说“它的使用可能会污染堆(heap)”时,它到底是什么意思?
还有,
新的@SafeVarargs
注解如何防止这种情况发生?
List<A> listOfAs = new ArrayList<>();
List<B> listOfBs = (List<B>)(Object)listOfAs; // points to a list of As
// if the heap never gets polluted, this should never throw a CCE
B b = listOfBs.get(0);
当你声明
public static <T> void foo(List<T>... bar)
时,编译器会将其转换为
public static <T> void foo(List<T>[] bar)
,然后再转换为
public static void foo(List[] bar)
这时就会出现错误,因为你可能会错误地将不正确的值分配到列表中,而编译器不会触发任何错误。例如,如果T
是一个String
,那么以下代码将在编译时没有错误,但在运行时会失败:
// 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("unchecked")
。@SuppressWarnings("varargs")
。有关这种第二种类型错误的很好解释,请参见Is @SafeVarargs an appropriate annotation for this method?和https://dev59.com/QGYq5IYBdhLWcg3wvzKm#14252221
参考文献:
Object[]
。只要不转换为 Object[]
,听起来应该没问题。 - djeikybstatic <T> void bar(T...args) { ((Object[])args)[0] = "a"; }
。然后调用 bar(Arrays.asList(1,2));
。 - djeikybObject[]
时才会出现危险,那么如果我不转换,为什么编译器会触发警告呢?毕竟,在编译时检查这一点应该相当容易(除非我将其传递给具有类似签名的另一个函数,在这种情况下,另一个函数应该触发警告)。
我不认为这真的是警告的核心(“如果你不转换,你就安全了”),而且我仍然不明白在哪种情况下我是安全的。 - Qw3rybar(Integer...args)
)而做完全相同的愚蠢事情。那么这个警告的意义是什么呢? - Vasiliy Vlasov@SafeVarargs
并不会防止堆污染的发生,而是规定编译器在编译使用它的代码时更加严格。
详细信息请参考http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html。
堆污染指的是,在对泛型接口执行操作时,如果它包含一个声明类型不同的其他类型,则会出现ClassCastException
。
Object[]
来保存这些参数。@SafeVarargs
抑制了编译器的警告,并不改变 JIT 的行为。@SafeVarargs
的问题。 - Paul Bellora原因是可变参数允许使用非参数化对象数组进行调用。因此,如果您的类型是List <A> ...,它也可以使用List[]非可变参数类型进行调用。
以下是一个示例:
public static void testCode(){
List[] b = new List[1];
test(b);
}
@SafeVarargs
public static void test(List<A>... a){
}
正如您所看到的,List[] b 可以包含任何类型的 consumer,但是这段代码可以编译通过。如果您使用 varargs,则可以正常使用,但是如果您在 type-erasure 后使用方法定义 - void test(List[]) - 那么编译器将不会检查模板参数类型。@SafeVarargs 将抑制此警告。
可能会出现参数化可变参数类型的堆污染
。 - Alexander Mills@SafeVarargs
感到困惑(就像我一样),这里有一个有用的解释,可以检查你的方法是否适合使用@SafeVarargs
进行注解。 - Qw3ry