JDK1.5之后,新增了自动拆、装箱功能,如以前创建一个Integer对象,需要 使用 “new”关键字
而现在Java中可以直接赋值如下:
Integer不是new出Integer对象,而是直接赋值,就是自动装箱过程。
Integer a = new Integer("100");
//JDK1.5之后
Integer b = 100;
int x = b;
再来测试如下代码:
/**
* JDK1.5之后,新增了自动拆、装箱功能
* 缓存以支持 JLS 要求的 -128 和 127(含)之间值的自动装箱的对象标识语义。
* 缓存在第一次使用时初始化。 缓存的大小可以由 -XX:AutoBoxCacheMax=<size> 选项控制。
* 在VM初始化过程中,java.lang.Integer.IntegerCache.high属性可能会被设置并保存在sun.misc.VM类的私有系统属性中
*
* 1、IntegerCache 缓存范围为 -128~127(默认范围)
* 2、大小可由 -XX:AutoBoxCacheMax调整
*/
public class IntegerTest {
public static void main(String[] args) {
Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1 == i2);
Integer i3 = -128;
Integer i4 = -128;
System.out.println(i3 == i4);
Integer i5 = -150;
Integer i6 = -150;
System.out.println(i5 == i6);
Integer i7 = 130;
Integer i8 = 130;
System.out.println(i7 == i8);
Integer i9 = new Integer("127");
Integer i10 = new Integer("127");
System.out.println(i9 == i10);
}
}
输出结果如下:
true
true
false
false
false
一、Integer缓存池 IntegerCache
我们可以看下 Integer.java 类 源码:
/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
IntegerCache 方法上注释大概意思
缓存以支持 JLS 要求的 -128 和 127(含)之间值的自动装箱的对象标识语义。
缓存在第一次使用时初始化。 缓存的大小可以由 -XX:AutoBoxCacheMax=<size> 选项控制。
在VM初始化过程中,java.lang.Integer.IntegerCache.high属性可能会被设置并保存在sun.misc.VM类的私有系统属性中。
由此得到2个重点关键字:
1、IntegerCache 缓存范围为 -128~127(默认范围)
2、大小可由 -XX:AutoBoxCacheMax 调整
可以得到解释缓存生成的范围是-128~127,参数可以启动之前配置JVM参数AutoBoxCacheMax进行修改
Integer类中存在一个缓冲范围,有一个规范叫JSL(Java Language Specification,java语言规范)对Integer的缓冲做了约束,规定其范围为:(-128-127)之间
这的IntegerCache有一个静态的Integer数组,在类加载时就将 -128 到 127 的Integer对象创建了,并保存在cache数组中,一旦程序调用valueOf 方法,如果 变量i 的值是在-128 到 127 之间就直接在cache缓存数组中去取Integer对象。
如果超出了范围,会从堆区new一个Integer对象来存放值
再看其它的包装器:
Boolean:(全部缓存)
Byte:(全部缓存)
Character(<= 127缓存)
Short(-128 — 127缓存)
Long(-128 — 127缓存)
Float(没有缓存)
Doulbe(没有缓存)
这时,我们看下上述代码的内存图
包装类的赋值方法是valueof但是从Java5.0(1.5)开始,JAVA虚拟机(Java Virtual Machine)可以完成基本类型和它们对应包装类之间的自动转换。因此我们在赋值、参数传递以及数学运算的时候像使用基本类型一样使用它们的包装类,但这并不意味着你可以通过基本类型调用它们的包装类才具有的方法。另外,所有基本类型(包括void)的包装类都使用了final修饰,因此我们无法继承它们扩展新的类,也无法重写它们的任何方法。
看一下valueof的源码了解缓存机制
public static Integer valueOf(int i) {
assert IntegerCache.high>= 127;
if (i >= IntegerCache.low&& i <= IntegerCache.high)
return IntegerCache.cache[i+ (-IntegerCache.low)];
return new Integer(i);
}
各个包装类缓存值范围 :
boolean:true和false
byte:-128~127
char:0~127
short:-128~127
int:-128~127
long:-128~127
float和double没有缓存
在缓存范围内的值相当于已经开辟好了一块空间,或者是已经new好了对象
1、Java中,在-128~127的Integer值并且以
Integer x = value;
的方式赋值的Integer值在进行==和equals比较时,都会返回true,因为Java里面对处在在-128~127之间的Integer值,用的是原生数据类型int,会在整数型常量内存池里,也就是说这之间的Integer值进行==比较时只是进行int原生数据类型的数值比较,而超出-128~127的范围,进行== 比较时是进行地址及数值比较
2、如果通过
Integer x = new Integer("127");
方式创建,还是和以前创建对象引用一样,在堆区中创建一个对象,然后将栈中引用指向这个对象,因此 i7 和 i8两个引用内存地址不同
注:Java中的Integer数值范围并不是-128到127。Java中的int占用4个字节,4*8=32位,去除一个符号位,实际表示数据大小的有32-1位;而是说有一个整数常量缓存池供Integer自动装箱时使用,提高效率。
二、IntegerCache范围修改
1、我们在JVM运行参数上加上 -XX:AutoBoxCacheMax=200
IDEA中,在界面位置依次选择
Run --> Eidt Configurations --> Modify options --> Add VM options
VM options 添加 -XX:AutoBoxCacheMax=200参数
添加之后就能在界面位置看到了,可以添加运行参数
Apply后 运行代码 查看效果
public static void main(String[] args) {
Integer a = 127;
Integer b = 127;
System.out.println(a == b);
Integer c = 128;
Integer d = 128;
System.out.println(c == d);
Integer e = 200;
Integer f = 200;
System.out.println(e == f);
Integer g = 201;
Integer h = 201;
System.out.println( g == h);
}
输出结果如下:
true
true
true
false
200时取自IntegerCache, 201则是不同指针的new Integer了。证明配置生效
2、我们在JVM运行参数上加上 -XX:AutoBoxCacheMax=120
public static void main(String[] args) {
Integer a = 127;
Integer b = 127;
System.out.println(a == b);
Integer c = 128;
Integer d = 128;
System.out.println(c == d);
Integer e = 100;
Integer f = 100;
System.out.println(e == f);
}
输出如下:
true
false
true
此时缓存池的值high是120,a、b = 127时 127应该是new的 a == b 应该是false
难道配置没生效,其实还是127?
其实不是我们设置的没生效,通过打印high的值,我们发现配置确实是生效了的,但没生效的原因是源码中做了判断。贴一段IntegerCache中为缓存池最大值赋值的方法
vm参数AutoBoxCacheMax的值与127做判断,取最大值,也就是说,如果我们设置的AutoBoxCacheMax参数比127小,则不会生效
结论:
-XX:AutoBoxCacheMax设置可以修改缓存池的最大范围,但需要大于127才能生效,小于等于127时,依然取的是默认值127