装箱拆箱
基本概念:
装箱既把一个基本数据类型的数据装成一个数据对象;
拆箱既把一个数据对象拆成一个基本数据类型的数据。
1.5之前
装箱
Float f1 = new Float(4.55);
Integer i1 = new Integer(55);
拆箱
int i2 = i1.intValue();
float f2 = f1.floatVlue();
1.5及以后 自动装箱拆箱
自动装箱就是可以把一个基本类型变量直接赋给对应的包装类变量,自动拆箱既把一个包装类对象直接赋值给一个基本类型变量。
自动装箱
Integer iz = 5;
自动拆箱
int ic = iz;
问题延伸:
1.5之前装箱是产生一个新的对象。而1.5之后自动装箱是否产生一个新的装箱对象。
面试问题:
public static void main(String[] args) {
Integer u = new Integer(2);
Integer u2 = new Integer(2);
Integer u3 = 2;
Integer u4 = 2;
Integer u5 = 12345;
Integer u6 = 12345;
System.out.println(u==u2);
System.out.println(u3==u2);
System.out.println(u3==u4);
System.out.println(u5==u6);
}
输出结果:
false
false
true
false
在此主要看最后两个为什么同为装箱一个为true一个为false。按照正常思维基本数据类型相等\==既成立。若为对象则引用同一个对象则==既成立。但是最后两个都是同样引用却产生了不同结果。
IntegerCache.java 私有类
privatestaticclassIntegerCache{
staticfinalintlow=-128;
staticfinalinthigh;
staticfinalIntegercache[];
static{
// high value may be configured by property
inth=127;
StringintegerCacheHighPropValue=sun.misc.VM
.getSavedProperty("java.lang.Integer.IntegerCache.high");
if(integerCacheHighPropValue!=null){
try{
inti=parseInt(integerCacheHighPropValue);
i=Math.max(i,127);
// Maximum array size is Integer.MAX_VALUE
h=Math.min(i,Integer.MAX_VALUE-(-low)-1);
}catch(NumberFormatExceptionnfe){
// If the property cannot be parsed into an int, ignore it.
}
}
high=h;
cache=newInteger[(high-low)+1];
intj=low;
for(intk=0;k<cache.length;k++)
cache[k]=newInteger(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assertIntegerCache.high>=127;
}
privateIntegerCache(){
}
}
该类为用户提供了基本类型实体类的缓存。当我们用自动装箱方法的时候系统调用的是“valueOf()”方法。
public static Integer valueOf(int i)
(api文档)返回一个Integer指定的int值的Integer实例。 如果不需要新的Integer实例,则该方法通常优先于构造函数Integer(int)使用 ,因为该方法可能通过缓存经常请求的值而产生明显更好的空间和时间性能。 此方法将始终缓存-128到127(含)范围内的值,并可能会超出此范围之外的其他值。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
如果值在-128到127之间,它就会返回该缓存的实例。这个就是为什么u3==u4为true。
问题延伸
当对象的属性是从数据库中查询出的是否试用这一准则。现在有两个类:
User
userDetailVO
这两个类同时拥有一个属性level
当属性为Integer时 数据库调取的对象值是一样的但是取==后在-128 到 127之间的为true不在这之间的为false。
// user
// 数据库中调取数据
User user = userAdminServiceimpl.selectUserDetailByIdTkmybatis(id);
// 数据库中调取数据
UserDetailVO userDetailVO = userAdminServiceimpl.selectUserDetailById(id);
System.out.println(user.getLevel() == userDetailVO.getLevel();
System.out.println(user.getLevel() == 555);
// 此处555 为db中数据 下面第二个例子 需要换为22
此时数据库中level值为555.
若属性为封装类输出
false
true
若属性为int类型输出:
true
true
此时数据库中level值为22.
若属性为封装类输出
true
true
若属性为int类型输出:
true
true
想避免这一问题在后台代码不同类中逻辑数据比较用==最好加上intValue()
其他缓存的对象
这种缓存行为不仅适用于Integer对象。我们针对所有整数类型的类都有类似的缓存机制。
有 ByteCache 用于缓存 Byte 对象
有 ShortCache 用于缓存 Short 对象
有 LongCache 用于缓存 Long 对象
有 CharacterCache 用于缓存 Character 对象
Byte,Short,Long 有固定范围: -128 到 127。对于 Character, 范围是 0 到 127。除了 Integer 可以通过参数改变范围外,其它的都不行。修改此处利用反射。
还有另外两个问题。数据库实体类创建的时候如果用了Integer两个不同对象中的两个integer属性是怎么对比的。
反射怎么修改low和high的值