简介
什么是堆净化呢?堆净化是指当参数化类型变量援用的对象不是该参数化类型的对象时而产生的。
咱们晓得在 JDK5 中,引入了泛型的概念,咱们能够在创立汇合类的时候,指定该汇合类中应该存储的对象类型。
如果在指定类型的汇合中,援用了不同的类型,那么这种状况就叫做堆净化。
产生堆净化的例子
有同学可能会问了,既然 JDK5 引入了泛型,为什么还会呈现堆净化呢?
这是一个好问题,让咱们看一个例子:
public void heapPollution1(){List normalList= Arrays.asList("www.flydean.com",100);
List<Integer> integerList= normalList;
}
下面的例子中,咱们应用 Arrays.asList 创立了一个一般的 List。
这个 List 中蕴含了 int 和 String 两种类型,当咱们将 List 赋值给 List<Integer> 的时候,java 编译器并不会去判断赋值 List 中的类型,integerList 中蕴含了非 Integer 的元素,最终导致在应用的时候会呈现谬误。
间接给 List<Integer> 赋值不会进行类型查看,那么如果咱们是间接向 List<Integer> 中增加元素呢?
咱们看下上面的例子:
private void addToList(List list, Object object){list.add(object);
}
@Test
public void heapPollution2(){List<Integer> integerList=new ArrayList<>();
addToList(integerList,"www.flydean.com");
}
下面的例子中,咱们定义了一个 addToList 办法,这个办法的参数是一个一般的 List,然而咱们传入了一个 List<Integer>。
后果,咱们发现 list.add 办法并没有进行参数类型校验。
下面的例子该怎么批改呢?
咱们须要在 addToList 办法的 List 参数中,也增加上类型校验:
private void addToList(List<Integer> list, Object object){list.add(object);
}
如果 addToList 是一个十分通用的办法怎么办呢?在 addToList 的参数中增加参数类型是事实的。
这个时候,咱们能够思考应用 Collections.checkedList 办法来将输出的 List 转换成为一个 checkedList,从而只接管特定类型的元素。
public void heapPollutionRight(){List<Integer> integerList=new ArrayList<>();
List<Integer> checkedIntegerList= Collections.checkedList(integerList, Integer.class);
addToList(checkedIntegerList,"www.flydean.com");
}
运行下面的代码,咱们将会失去上面的异样:
java.lang.ClassCastException: Attempt to insert class java.lang.String element into collection with element type class java.lang.Integer
更通用的例子
下面咱们定义了一个 addToList 办法,因为没有做类型判断,所以可能会呈现堆净化的问题。
有没有什么方法既能够通用,又能够防止堆净化呢?
当然有的,咱们看上面的实现:
private <T> void addToList2(List<T> list, T t) {list.add(t);
}
public <T> void heapPollutionRight2(T element){List<T> list = new ArrayList<>();
addToList2(list,element);
}
下面的例子中,咱们在 addToList 办法中定义了一个参数类型 T,通过这样,咱们保障了 List 中的元素类型的一致性。
可变参数
事实上,办法参数能够是可变的,咱们思考上面的例子:
private void addToList3(List<Integer>... listArray){Object[] objectArray = listArray;
objectArray[0]= Arrays.asList("www.flydean.com");
for(List<Integer> integerList: listArray){for(Integer element: integerList){System.out.println(element);
}
}
}
下面的例子中咱们的参数是一个 List 的数组,尽管 List 中的元素类型固定了,然而咱们能够从新赋值给参数数组,从而实际上批改掉参数类型。
如果下面 addToList3 的办法参数批改为上面的形式,就不会呈现问题了:
private void addToList4(List<List<Integer>> listArray){
这种状况下,List 的类型是固定的,咱们无奈通过从新赋值的形式来批改它。
本文的例子:
learn-java-base-9-to-20/tree/master/security
本文已收录于 http://www.flydean.com/java-security-code-line-heap-pollution/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」, 懂技术,更懂你!