📜  什么是Java中的堆污染以及如何解决它?

📅  最后修改于: 2022-05-13 01:54:55.604000             🧑  作者: Mango

什么是Java中的堆污染以及如何解决它?

什么是堆污染?

堆污染意味着我们的堆内存中有坏数据。在Java语言中,堆污染是当参数化类型的变量指向不属于该参数化类型的对象时发生的情况。

如何检测堆污染?

通常,编译器仅在编译时检测堆污染情况并抛出未经检查的警告消息。

运行时,有可能出现堆污染,这将导致ClassCastException 。堆污染是指堆内存中的坏数据。这里的坏数据是 X 类型的对象,但 Y 类型的对象是预期的,它将在运行时抛出 ClassCastException。

让我们用程序来理解堆污染:

// Program to illustrate Heap pollution situation
  
import java.util.*;
  
class Geeks {
    public static void main(String[] args)
    {
  
        // Creating a List of type String
        List listOfString = new ArrayList<>();
        listOfString.add("Geeksforgeeks");
  
        // Creating a List of type Integer which holds
        // the reference of a List of type String
        // Here compiler will detect that
        // there is a chance of Heap pollution
        // Compiler will throw an unchecked warning
        // at the compile-time only
        List listOfInteger
            = (List)(Object)listOfString;
  
        // Here we are trying to access
        // firstElement of listOfInteger which holds
        // the reference of a List of type String
        // and trying to store it into
        // one variable of type Integer
        Integer firstElement
            = listOfInteger.get(0);
        System.out.println(firstElement);
    }
}

编译时控制台:

prog.java:12: warning: [unchecked] unchecked cast
        List listOfInteger = (List)(Object)listOfString;
                                                     ^
  required: List
  found:    Object
1 warning

输出:

如何处理堆污染?

// Program to illustrate Heap pollution with respect to varargs
  
import java.util.*;
  
class Geeks {
    public static void merge(List... stringList)
    {
        // Here we are an array of type Object holds
        // reference of an array of type List
        Object[] arr = stringList;
        List temp = new ArrayList();
        temp.add(420);
  
        // Here we are trying to assign temp
        // of type List into arr[0]
        // which is of type List
  
        // Here ClassCastException will be thrown
        arr[0] = temp;
  
        String firstEle = stringList[0].get(0);
        System.out.println(firstEle);
    }
  
    // Driver code
    public static void main(String args[])
    {
        List list1 = new ArrayList<>();
        List list2 = new ArrayList<>();
        List list3 = new ArrayList<>();
        list1.add("Geeks");
        list2.add("for");
        list3.add("geeks");
  
        merge(list1, list2, list3);
    }
}

编译时控制台:

prog.java:4: warning:
 [unchecked] Possible heap pollution from
             parameterized vararg type List
    public static void merge(List... stringList)
                                             ^
prog.java:23: warning:
 [unchecked] unchecked generic array creation
             for varargs parameter of type List[]
        merge(list1, list2, list3);
             ^
2 warnings

输出:

Exception in thread "main" java.lang.ClassCastException:
 java.lang.Integer cannot be cast to java.lang.String
    at Geeks.merge(File.java:10)
    at Geeks.main(File.java:23)

注意:如果我们不想在编译时出现警告,那么我们可以在方法上方使用 @SafeVarargs 注释。如果我们知道该方法不包含任何堆污染情况,那么您可以使用 @SafeVarargs 对其进行注释以抑制警告。这并不意味着它会允许我们的代码进行堆污染。这意味着如果代码中存在 Heap 污染的可能性,它会在运行时抛出ClassCastException

如何防止堆污染情况?

我们无法防止堆污染情况,但我们可以遵循一些可以帮助我们防止堆污染的规则,例如:

  • 不要将 varargs 参数用于泛型类型或将 Object 数组转换为泛型类型的数组。
  • 不要将 varargs 参数或泛型数组公开给任何其他方法。