java安全编码指南之:堆污染Heap pollution
简介
什么是堆污染呢?堆污染是指当参数化类型变量引用的对象不是该参数化类型的对象时而发生的。
我们知道在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的时候,java编译器并不会去判断赋值List中的类型,integerList中包含了非Integer的元素,最终导致在使用的时候会出现错误。
直接给List赋值不会进行类型检查,那么如果我们是直接向List中添加元素呢?
我们看下下面的例子:
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。
结果,我们发现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的类型是固定的,我们无法通过重新赋值的方式来修改它。
更多精彩内容
1 |
JDK15真的来了! |
---|---|
2 |
一文解开java中字符串编码的小秘密 |
3 |
java安全编码指南之:表达式规则 |
- 分布式系统CAP理论
- 美媒盘点2018年将改变世界的四大技术趋势
- 如果你想深刻理解ASP.NET Core请求处理管道,可以试着写一个自定义的Server
- 路面能发电,智慧交通不遥远
- 小程序:企鹅帝国身后,微信帝国正悄悄露出冰山一角!
- ASP.NET MVC路由扩展:路由映射
- 如何改善遗留的代码库
- ASP.NET的路由系统:根据路由规则生成URL
- ASP.NET Core 1.0中实现文件上传的两种方式(提交表单和采用AJAX)
- 通过3个Hello World应用来了解ASP.NET 5应用是如何运行的(1)
- 工业X.0将至 企业数字化转型该怎么做?
- 通过3个Hello World应用来了解ASP.NET 5应用是如何运行的(2)
- 通过3个Hello World应用来了解ASP.NET 5应用是如何运行的(3)
- 为什么说2018年互联网创业机会将变少
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- django 多数据库及分库实现方式
- Python气泡提示与标签的实现
- Django之choices选项和富文本编辑器的使用详解
- Android使用RSA加密和解密的示例代码
- Android布局之帧布局FrameLayout详解
- Okhttp3实现爬取验证码及获取Cookie的示例
- Android监听系统来电并弹出提示窗口
- 你该知道的Gradle配置知识总结
- Android布局之绝对布局AbsoluteLayout详解
- django实现模型字段动态choice的操作
- 详解ASP.NET Core 处理 404 Not Found
- Python AutoCAD 系统设置的实现方法
- Python如何操作office实现自动化及win32com.client的运用
- android Palette调色板使用详解
- python 穷举指定长度的密码例子