简介什么是堆污染?当参数化类型变量引用的对象不是参数化类型的对象时,就会发生堆污染。
我们知道在JDK5中引入了泛型的概念。
创建集合类时,我们可以指定应该存储在集合类中的对象的类型。
如果在一组指定类型中引用了不同类型,则这种情况称为堆污染。
有些学生可能会问到堆污染的例子,因为JDK5引入了泛型,为什么堆污染仍然会发生?这是一个很好的问题,让我们看一个例子:public void heapPollution1(){List normalList = Arrays.asList(“ www.flydean.com”,100); ListintegerList = normalList; }在上面的示例中,我们使用了数组。
asList创建一个普通列表。
该列表包含int和String两种类型。
当我们将List分配给List时,Java编译器将不会判断分配的List中的类型。
IntegerList包含非Integer元素,最终导致使用会出现错误。
直接分配给List不会执行类型检查,那么如果我们直接向List中添加元素怎么办?让我们看下面的示例:private void addToList(List list,Object object){list.add(object);} @Test public void heapPollution2(){ListintegerList = new ArrayList& lt;& gt;(); addToList(integerList,“ www.flydean.com”);}在上面的示例中,我们定义了addToList方法。
该方法的参数是一个普通的List,但是我们传入了一个List。
结果,我们发现list.add方法没有执行参数类型验证。
上面的例子如何修改?我们需要向addToList方法的List参数添加类型验证:private void addToList(Listlist,Object object){list.add(object);}如果addToList是一个非常常见的方法,该怎么办?将参数类型添加到addToList的参数是现实的。
目前,我们可以考虑使用Collections.checkedList方法将输入List转换为checkedList,以便仅接收特定类型的元素。
public void heapPollutionRight(){ListintegerList = new ArrayList& lt;& gt;(); ListcheckedIntegerList = Collections.checkedList(integerList,Integer.class); addToList(checkedIntegerList,“ www.flydean.com”); }运行上面的代码,我们将获得以下异常:java.lang.ClassCastException:尝试将类java.lang.String元素插入元素类型为java.lang.Integer的集合中。
方法,因为没有类型判断,所以可能会发生堆污染的问题。
在避免堆污染的同时,有什么可以通用的方法吗?当然,我们来看下面的实现:private void addToList2(Listlist,T t){list.add(t);} public void heapPollutionRight2(T element){Listlist = new ArrayList& lt;& gt;( );在上面的示例中,我们在addToList方法中定义了参数类型T。
这样,我们确保列表中元素类型的一致性。
可变参数实际上,方法参数可以是可变的。
我们考虑以下示例:private void addToList3(List ... listArray){Object [] objectArray = listArray; objectArray [0] = Arrays.asList(“ www.flydean.com”); for(ListintegerList:listArray){for(Integer element:integerList){System.out.println(element);}}}在上面的示例中,我们的参数是List的数组,尽管Element类型是固定的,但是我们可以重新分配参数数组以实际修改参数类型。
如果将上述addToList3的方法参数修改为以下方式,将不会有问题:private void addToList4(ListlistArray){在这种情况下,List的类型是固定的,我们无法通过重新分配进行修改。