简介
什么是堆净化呢?堆净化是指当参数化类型变量援用的对象不是该参数化类型的对象时而产生的。
咱们晓得在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/最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」,懂技术,更懂你!