发现问题
项目里有发现“神奇”的代码,先不考虑代码逻辑以及实现方法是否合理,原来代码实现大致是这样:
## department 对象
public class Department{
private Integer departmentId;
private String departmentName;
private Integer pDepartmentId;
private List<user> departmentMember;
## 省略get\set方法
}
## user 对象
publci class User{
private Integer userId;
private String name;
##所属部门编号
private Integer departmentId;
## 省略get/set方法
}
## 组织部门人员信息
## 获取部门信息
List<Department> departments= departmentService.getAllDepartments();
## 获取人员信息
List<User> users=userService.getAllUsers();
## 迭代,拼接数据
for(Department dep:departments){
for(User user:users){
//坑点
if(user.getDepartmentId() == dep.getDepartmentId()){
if(null == dep.getDepartmentMember() ){
dep.setDepartmentMember(new ArrayList<User>());
}else{
dep.getDepartmentMember().add(user);
}
}
}
}
坑点,看到伪码大概都能知道了,就是Integer的比较,应该使用 equals() 或者 转换成 int进行比较,但这里隐藏了Java
的一个特性,使得 == 的运行符合预期,不正常变得正常了!!!但是“正常”还得结合特定的数据,造来:
CREATE TABLE `b_department` (
`department_id` int(11) NOT NULL AUTO_INCREMENT,
`department_name` varchar(50) DEFAULT NULL,
`p_department_id` int(11) DEFAULT NULL,
PRIMARY KEY (`department_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
如果部门数据比较少,数据库中的department_id
刚好都小于127,程序运行的符合预期!!! Why?!!
在这里:
为了节省内存,对于下列包装对象的两个实例,当它们的基本值相同时,他们总是 ‘相等’的
Boolean
Byte
Character, \u0000 - \u007f(7f是十进制的127)
Integer, -128 — 127
延伸 :JVM通过参数调整包裹对象缓存大小
使用Oracle/Sun JDK 6,在server模式下,使用-XX:AutoBoxCacheMax=NNN参数即可将Integer的自动缓存区间设置为[-128,NNN]
注意: 区间的下界固定在-128不可配置,在client模式下该参数无效。
测试代码:
public class TestIntegerCache {
public static void main(String[] args) {
Integer a = 1024;
Integer b = 1024;
System.out.println(a == b);
Integer c = 1025;
Integer d = 1025;
System.out.println(c == d);
Integer e = 20000;
Integer f = 20000;
System.out.println(e == f);
}
}
shell >java TestIntegerCache
false
false
false
shell >java -server TestIntegerCache
false
false
false
shell >java -Djava.lang.Integer.IntegerCache.high=1024 TestIntegerCache
true
false
false
shell >java -server -Djava.lang.Integer.IntegerCache.high=1024 TestIntegerCache
true
false
false
shell >java -Djava.lang.Integer.IntegerCache.high=1025 TestIntegerCache
true
true
false
shell >java -server -Djava.lang.Integer.IntegerCache.high=1025 TestIntegerCache
true
true
false
shell >java -XX:AutoBoxCacheMax=1024 TestIntegerCache
Unrecognized VM option 'AutoBoxCacheMax=1024'
Could not create the Java virtual machine.
shell >java -server -XX:AutoBoxCacheMax=1024 TestIntegerCache
true
false
false
shell >java -server -XX:AutoBoxCacheMax=1025 TestIntegerCache
true
true
false
shell >java -server -XX:+AggressiveOpts TestIntegerCache
true
true
true