简介

什么是堆污染呢?堆污染是指当参数化类型变量引用的对象不是该参数化类型的对象时而发生的。

我们知道在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的类型是固定的,我们无法通过重新赋值的方式来修改它。

本文的例子:

learn-java-base-9-to-20/tree/master/security

本文已收录于 http://www.flydean.com/java-security-code-line-heap-pollution/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

java安全编码指南之:堆污染Heap pollution的更多相关文章

  1. java安全编码指南之:基础篇

    目录 简介 java平台本身的安全性 安全第一,不要写聪明的代码 在代码设计之初就考虑安全性 避免重复的代码 限制权限 构建可信边界 封装 写文档 简介 作为一个程序员,只是写出好用的代码是不够的,我 ...

  2. java安全编码指南之:Mutability可变性

    目录 简介 可变对象和不可变对象 创建mutable对象的拷贝 为mutable类创建copy方法 不要相信equals 不要直接暴露可修改的属性 public static fields应该被置位f ...

  3. java安全编码指南之:字符串和编码

    目录 简介 使用变长编码的不完全字符来创建字符串 char不能表示所有的Unicode 注意Locale的使用 文件读写中的编码格式 不要将非字符数据编码为字符串 简介 字符串是我们日常编码过程中使用 ...

  4. java安全编码指南之:输入校验

    目录 简介 在字符串标准化之后进行校验 注意不可信字符串的格式化 小心使用Runtime.exec() 正则表达式的匹配 简介 为了保证java程序的安全,任何外部用户的输入我们都认为是可能有恶意攻击 ...

  5. java安全编码指南之:声明和初始化

    目录 简介 初始化顺序 循环初始化 不要使用java标准库中的类名作为自己的类名 不要在增强的for语句中修改变量值 简介 在java对象和字段的初始化过程中会遇到哪些安全性问题呢?一起来看看吧. 初 ...

  6. java安全编码指南之:Number操作

    目录 简介 Number的范围 区分位运算和算数运算 注意不要使用0作为除数 兼容C++的无符号整数类型 NAN和INFINITY 不要使用float或者double作为循环的计数器 BigDecim ...

  7. java安全编码指南之:可见性和原子性

    目录 简介 不可变对象的可见性 保证共享变量的复合操作的原子性 保证多个Atomic原子类操作的原子性 保证方法调用链的原子性 读写64bits的值 简介 java类中会定义很多变量,有类变量也有实例 ...

  8. java安全编码指南之:异常处理

    目录 简介 异常简介 不要忽略checked exceptions 不要在异常中暴露敏感信息 在处理捕获的异常时,需要恢复对象的初始状态 不要手动完成finally block 不要捕获NullPoi ...

  9. java安全编码指南之:死锁dead lock

    目录 简介 不同的加锁顺序 使用private类变量 使用相同的Order 释放掉已占有的锁 简介 java中为了保证共享数据的安全性,我们引入了锁的机制.有了锁就有可能产生死锁. 死锁的原因就是多个 ...

随机推荐

  1. 手动SQL注入总结

    1.基于报错与union的注入 注意:union联合查询注入一般要配合其他注入使用 A.判断是否存在注入,注入是字符型还是数字型,有没过滤了关键字,可否绕过 a.如何判断是否存在注入 一般有一下几种 ...

  2. 土题大战Vol.0 A. 笨小猴 思维好题

    土题大战Vol.0 A. 笨小猴 思维好题 题目描述 驴蛋蛋有 \(2n + 1\) 张 \(4\) 星武器卡片,每张卡片上都有两个数字,第 \(i\) 张卡片上的两个数字分别是 \(A_i\) 与 ...

  3. 每天都在用String,你真的了解吗?

    1.String概述 java.lang.String 类代表字符串.Java程序中所有的字符串文字(例如"abc")都可以被看作是实现此类的实例 String 中包括用于检查各个 ...

  4. Windows 安装 kafka

    1.kafka下载地址:http://kafka.apache.org/downloads 解压:kafka_2.12-2.6.0.tgz 2.配置zookeeper 进入config目录找到文件zo ...

  5. PythonCrashCourse 第九章习题

    创建一个名为Restaurant 的类,其方法__init__() 设置两个属性: restaurant_name 和cuisine_type 创建一个名为describe _restaurant ( ...

  6. Docker 的前世今生

    虚拟化 「要解释清楚 Docker,首先要解释清楚容器(Container)的概念」.要解释容器的话,就需要从操作系统说起.操作系统太底层,细说的话一两本书都说不清楚.这里就一句话来总结一下:操作系统 ...

  7. .NET Core + K8S + Apollo 玩转配置中心

    1.引言 Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性,适用于微服务配置管理 ...

  8. 线程池之Executor框架

    线程池之Executor框架 Java的线程既是工作单元,也是执行机制.从JDK5开始,把工作机单元和执行机制分离开来.工作单元包括Runnable和Callable,而执行机制由Executor框架 ...

  9. Spring官方宣布:新的Spring OAuth2.0授权服务器已经来了

    1. 前言 记不记得之前发过一篇文章Spring 官方发起Spring Authorization Server 项目.该项目是由Spring Security主导的一个社区驱动的.独立的孵化项目.由 ...

  10. 牛客网PAT练兵场-旧键盘打字

    题目地址:https://www.nowcoder.com/pat/6/problem/4059 题解:用数组下标标记,直接模拟 /** * *作者:Ycute *时间:2019-12-01-21.3 ...