版权声明:转载请注明出处! 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);
}