浅谈java 堆污染

版权声明:转载请注明出处! https://blog.csdn.net/zongf0504/article/details/85716425

java 堆污染

Heap pollution(堆污染), 指的是当把一个不带泛型的对象赋值给一个带泛型的变量时, 就有可能发生堆污染.
由于定义带泛型变量时并不强制指定泛型类型, 因此如果借此发生狸猫换太子的操作的话, 那么就会导致堆污染. 堆污染在编译时并不会报错, 只会在编译时提示有可能导致堆污染的警告. 在运行时,如果发生了堆污染, 那么就会抛出类型转换异常.

1. 堆污染场景

1.1 堆污染示例一

public static void main(String[] args) {

    // list 定义时未指定泛型,实际上集合中存储为Integer类型
    List list = new ArrayList<Integer>();
    list.add(1);

    // 将无泛型的list对象,赋值给指定类型的strList变量, 此处已经发生堆污染
    List<String> strList = list;

    // 抛出异常 java.lang.ClassCastException
    String str = strList.get(0);
    
}

1.2 堆污染示例二

java 语言中不允许创建泛型数组, 所以当可变参数为带泛型的可变数组时, 方法内只能用不带泛型的数组接收.

public static void function(List<String> ... strListArray) {
    // java 语言不允许创建泛型数组,所以只能使用不带泛型的数组List[] 接收参数
    List[] listArray = strListArray;

    // 创建一个指定泛型的list
    List<Integer> intList = Arrays.asList(1);

    // 发生堆污染: listArray[0] 为无泛型List, intList 为有泛型List, 此处发生堆污染
    listArray[0] = intList;

    // 抛出异常
    String str = strListArray[0].get(0);
}
public static void main(String[] args) {

    List<String> strList1 = new ArrayList<>();
    strList1.add("a");
    function(strList1);
}

1.3 示例三

泛型的狸猫换太子

public static void main(String[] args) {

    List<Integer> intList = new ArrayList<>();
    intList.add(1);

    List<String> strList = new ArrayList<>();
    strList.add("a");

//  如果直接将intList 赋值给lst 编译会报错, 因为类型不一致
//  List<String> lst = intList;

//  借助泛型可以不指定类型可以进行狸猫换太子操作
    List list = intList;
    List<String> lst = list;

//  在获取参数时,会抛出类型转换异常
    System.out.println(lst.get(0));

}

2. 堆污染忽略警告方式

默认情况下, 当有可能产生堆污染时,编译器会提示警告信息, 如果确认不会产生堆污染, 又不想看到警告提示的话, 可以通过以下方式取消提示.

  • @SuppressWarnings(“unchecked”): 加上方法或类上, 取消警告提示. 可以取消的不止堆污染警告
  • @SafeVarargs: Java7 专门用来抑制堆污染(Heap pollution)警告提供的注解.
@SafeVarargs
public static void function(List<String> ... strListArray) {
    // java 语言不允许创建泛型数组,所以只能使用不带泛型的数组List[] 接收参数
    List[] listArray = strListArray;

    // 创建一个指定泛型的list
    List<Integer> intList = Arrays.asList(1);

    // 发生堆污染: listArray[0] 为无泛型List, intList 为有泛型List, 此处发生堆污染
    listArray[0] = intList;

    // 抛出异常
    String str = strListArray[0].get(0);
}

猜你喜欢

转载自blog.csdn.net/zongf0504/article/details/85716425