jdk1.5以后
用Integer举例
Integer a = 3; 这是自动装箱
int i = new Integer(2); 这是自动拆箱
就是基本类型和其对应的包装类型在需要的时候可以互相转换,具体过程由编译器完成
比如自动装箱:
Integer a=3;
其实编译器调用的是static Integer valueOf(int i)这个方法
查阅JDK知道,
valueOf(int i)返回一个表示指定的 int 值的 Integer 对象
那么就变成这样: Integer a=3; => Integer a=Integer.valueOf(3);
对应的 int intValue() 返回该 Integer对象的int值,是拆箱
我们再来看Integer缓存,
下面是IntegerCache类的源码,我加上了注释,便于讨论
private static class IntegerCache //定义类名 { static final int high; static final Integer cache[]; //cache缓存是一个存放Integer类型的数组 static //初始化 { final int low = -128; //最小值是固定的 int h = 127; //最大值暂时是127 if (integerCacheHighPropValue != null) //这段if代码不用深究,是一些判断,我看得眼花啊 { int i = Long.decode(integerCacheHighPropValue).intValue(); i = Math.max(i, 127); h = Math.min(i, Integer.MAX_VALUE - -low); } high = h; //此时high就是127 cache = new Integer[(high - low) + 1]; //有256个元素 int j = low; //j的初始值是-128 for(int k = 0; k < cache.length; k++) //缓存区间数据 cache[k] = new Integer(j++); //将-128~127包装成256个对象存入缓存 } private IntegerCache(){} //构造方法,不需要构造什么 }
再来看valueOf方法
public static Integer valueOf(int i) { if(i >= -128 && i <= IntegerCache.high) { //如果i在-128~127之间,就直接在缓存中取出i的Integer类型对象 return IntegerCache.cache[i + 128]; } else { return new Integer(i); //否则就在堆内存中创建 } }
valueOf方法会自动调用IntegerCache这个类,
IntegerCache初始化后内存中就有Integer缓冲区cache[]了,
-128~127区间的int值有其对应的的包装对象
java使用该机制是为了达到最小化数据输入和输出的目的,这是一种优化措施,提高效率
其他的包装器:
Boolean: (全部缓存)
Byte: (全部缓存)
Character ( <=127 缓存)
Short (-128~127 缓存)
Long (-128~127 缓存)
Float (没有缓存)
Doulbe (没有缓存)
补充下我对Integer缓冲池对理解:
(这个观点是我在网上看到的一些资料加上自己看源码后的一些推断,但没有在哪本书上看到过这种说法,最近打算看think in java)
缓冲池是java对系统的优化,它是一种管理内存的机制,是一种数据结构,它可以管理多个缓冲区,IntegerCache就是一个缓冲区,cache[]数组中保存的是指向Integer类型对象的指针,虽然Integer缓冲对象是new出来的,但是是由缓冲池管理,欢迎一起讨论.
然后回答一个网友的提问,问题比较典型,我贴到上面来,
先说String str = "aaa";
"aaa"本身就是一个字符串对象,它在编译时就被定义在了数据区,在运行时直接创建到常量池,或者说数据区,而str是当程序运行到这句代码时系统在内存的栈区分配的一个指针变量,指向了常量池中的"aaa"对象,
如果是String str = new String("aaa"); 在编译时,"aaa"对象被创建到数据区,在运行时执行到new String()时,程序动态的开辟一块内存空间,
并将数据区中的"aaa"对象复制一份到堆中,并返回一个引用给str所在栈中,此时这一条语句创建了1个新的String对象。加上原来在数据区中的对象一共2个对象,不知道我说的对不对,请大家指教..
还有一网友问 "Doulbe没有缓存,能说为啥莫?"
Doulbe (没有缓存)
我也是在网上看到的,我查了下java文档源码
public static Double valueOf(double d) {
return new Double(d);
}
代码中确实没有用到缓冲
对比Integer的valueOf方法,是不一样的,所以才有这个结论的吧!
====================================================
知道了这些原理
我们再来看一些网上关于java的有趣问题,就能知道答案了
下面我们对一网友帖子中的问题的做解答,我当时也是看到这个帖子才baidu学到这些内容的
http://xiaoyu1985ban.iteye.com/blog/1384191
主题:java迷题:等于,还是不等于?
代码片段1
public static void main(final String[] args) {
Integer a = new Integer(100);
Integer b = 100;
System.out.println(a == b);
}
解答:
结果输出 false
因为new Integer(100)是指明了再堆内存中创建对象
而Integer b = 100; 这句是自动装箱,
得到的是Integer缓冲池中的对象,是这句代码return IntegerCache.cache[100 + 128]
明显a和b的地址是不一样的,不是同一个对象
代码片段2
public static void main(final String[] args) {
Integer a = 100;
Integer b = 100;
System.out.println(a == b);
}
解答:
结果输出 true
a和b指向了同一个对象,都是IntegerCache.cache[100 + 128]
代码片段3
public static void main(final String[] args) {
Integer a = 156;
Integer b = 156;
System.out.println(a == b);
}
解答:
结果输出 false
由于156大于128,它的包装对象不在缓冲池中,而是执行 return new Integer(156);
new了2次,都在堆内存中,但地址不一样
代码片段4
public static void main(final String[] args) {
Integer a = Integer.valueOf(100);
Integer b = 100;
System.out.println(a == b);
}
解答:
结果输出 true
我们上面说过了,Integer b = 100 就相当于Integer b=Integer.valueOf(100)
所以a和b指向缓冲池中的同一对象