是否存在在没有显式“Object[]”转换的情况下发生参数化可变参数类型的堆污染的情况?

Is there any scenario where heap pollution from parameterized vararg type occurs without an explicit `Object[]` conversion?

我一直在查看有关使用不可具体化可变参数时堆污染的各种答案和文章。我发现的所有示例都使用 Object[] 转换,然后是数组元素写入。堆污染似乎只以这种方式发生,例如:

public void example(List<Integer>... lists) {
    // lists[0] = Collections.singletonList("A!");
    Object[] objects = lists;
    objects[0] = Collections.singletonList("B!"); // (pollutes!)
}

其他一些文章 () 似乎也不正确或完全具有误导性:

So now we have a List<String> that actually contains an Integer, and it's floating around, safely.

答案中提供的代码从不修改列表本身,只是 faultyMethod 范围内的临时可变参数数组。这个 runnable demo 表明这两个列表都没有被污染并且都保留了它们原来的 String 对象(与暗示它们被 Integer 污染的答案相反)。


我现在有两个问题:

  1. 为什么编译器需要在每种可能的方法上警告我们,而绝大多数方法都不会转换为 Object[] - 当然最好只警告有问题的方法Object[] 行本身?也许存在这样一种情况,即在没有任何显式 Object[] 转换的情况下会发生“参数化可变参数类型可能造成的堆污染”?

  2. 上一个 SO 问题的答案不正确还是我误解了该陈述?

Why does the compiler need to warn us on every possible method when the vast majority of them will not be converting to

您有一个类型的变量,例如List<Integer>[] 在这里,但它实际上可以包含其他内容。是的,可以选择将 lists 参数视为具有 [TAINTED]{List<Integer>[]} 类型,并让这种巫毒魔法无法表达的类型像普通的 ole List<Integer>[] 一样,例如使用 foo = lists[0] 访问它,但如果您尝试使用例如写入它,它会发出警告lists[0] = ...;.

但 java 没有 - 这会使类型系统复杂化,需要为编译器引入类型的概念,这意味着:“它就像这种类型的数组,除非你写到它,在这种情况下,您现在特别需要产生警告,而对于获取此类型的其他方式,您不需要。

你的人脑会着眼于整件事,并对整件事进行推理。编写计算机代码是为了抽象、模块化和限制。编译器将表达式限制为 'they are of this type',它们不会“开始”记住:哦,是的,这是一个 List<Integer>[] 但它是基于可变参数的,所以我需要仔细检查是否代码是否尝试用这个东西破坏堆。

请注意,@SafeVarargs 试图缓解其中的一些问题,您应该研究一下。

Is the answer to the previous SO question incorrect or am I misinterpreting the statement?

是的,那个 14 分的公认答案确实是彻头彻尾的废话(这不是讽刺)。我不知道为什么它被评为这样。没有意义。

泛型可变参数的主要内在危险是,如果你使用数组 本身 并对其进行除使用它并丢失它之外的任何操作:如果你通过它数组到另一个方法*,或将其存储在一个字段中, 是一个等待发生的潜在灾难。如果您只是从中读取或循环遍历它,那没关系。

*) 当然,如果您将数组传递给自己的方法递归地遵守我 [A] 从中读取的规则,and/or [B] 循环遍历它,and/or[C]递归符合这个定义的方法,那就没有问题了。只要该数组永远不会存储在字段中或被写入,就没有关系。您链接到的答案没有 write/store,因此没有意义。