问题引出
Integer最大/小值
java中Integer是有最大值和最小值的
最大值为
Integer.MAX_VALUE = 2147483647
最小值为
Integer.MIN_VALUE = -2147483648
注意:两个值并没有互为相反数
有
Integer.MAX_VALUE + 1 = Integer.MIN_VALUE
同理
Integer.MIN_VALUE - 1 = Integer.MAX_VALUE
Integer最大/小值案例
但是用到了这样的一个案例:
public static void test() { //true Integer a1 = 127, b1 = 127; System.out.println(a1 == b1); //false Integer a2 = new Integer(127); Integer b2 = new Integer(127); System.out.println(a2 == b2); //false Integer a3 = 128, b3 = 128; System.out.println(a3 == b3); //true Integer a4 = 128, b4 = 128; System.out.println(a4.equals(b4)); } public static void main(String[] args) { test(); }
比较答案:
true false false true
结果原因
- 第一个使用"=="判断 Integer a1 = 127 和 Integer b1 = 127
相等原因:Integer的取值范围是-128~127
- 第二个使用"=="判断Integer a2 = new Integer(127) 和 Integer b2 = new Integer(127)
不相等原因:装箱时,java为了提高效率,IntegerCache类中有一个数组将-128<=i<=127范围之内的数据打包成缓存里的Integer对象了,因此不用new,这个区间里的值用直接=赋值方法得到的变量地址就是同一个,而超出这个范围的数值就会new一个Integer对象出来
- 第三个使用"=="判断Integer a3=128 和 Integer b3 = 128
不相等原因:因为Integer类型赋值范围在-128—127之间,超出这个范围的数值就会重新new一个Integer对象出来,直接用==去比较是比较a3和b3的地址,a3和b3的地址是不相等的
- 第四个使用使用"=="equals()方法判断Integer a4=128 和 Integerb4 = 128
相等原因:使用equals()方法比较的是a4和b4的数值
注意点:"=="可以用于原始值进行比较,也可以用于对象进行比较,当用于对象与对象之间比较时,比较的不是对象代表的值,而是检查两个对象是否是同一对象,这个比较过程中没有自动装箱发生。进行对象值比较不应该使用”==“,而应该使用对象对应的equals方法。
小总结
JVM会自动维护八种基本类型的常量池,int常量池中初始化-128~127的范围,所以当为Integer i=127时,在自动装箱过程中是取自常量池中的数值,而当Integer i=128时,128不在常量池范围内,所以在自动装箱过程中需new 128,所以地址不一样。
上面就用到了Java自动装箱的概念,下面我们来深入了解一下:
Integer 自动装箱
IntegerCache缓存
Integer 缓存是 Java 5 中引入的一个有助于节省内存、提高性能的特性。
Integer中有个静态内部类IntegerCache,里面有个cache[],也就是Integer常量池,常量池的大小为一个字节(-128~127)。JDK源码如下(摘自JDK1.8源码):
/** * 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 -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) { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low)); } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); } private IntegerCache() {} }
当创建Integer对象时,不使用new Integer(int i)语句,大小在-128~127之间,对象存放在Integer常量池中。
例如:Integer a = 10;
调用的是Integer.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); }
这也是自动装箱的代码实现。
Java自动装箱
JAVA将基本类型自动转换为包装类的过程称为自动装箱(autoboxing)。
实际上在 Java 5 中引入这个特性的时候,范围是固定的 -128 至 +127。后来在Java 6 后,最大值映射到 java.lang.Integer.IntegerCache.high,可以使用 JVM 的启动参数设置最大值。(通过 JVM 的启动参数 -XX:AutoBoxCacheMax=size 修改)
缓存通过一个 for 循环实现。从小到大的创建尽可能多的整数并存储在一个名为 cache 的整数数组中。这个缓存会在 Integer 类第一次被使用的时候被初始化出来。以后,就可以使用缓存中包含的实例对象,而不是创建一个新的实例(在自动装箱的情况下)。
测试情况:
int i = 10; int i1 = 10; Integer in1 = 10; Integer in2 = 10; Integer in3 = new Integer(10); Integer in4 = new Integer(10); Integer in5 = 199; Integer in6 = 199; System.out.println(i == i1); // true System.out.println(i == in1); // true System.out.println(i == in2); // true System.out.println(i == in3); // true System.out.println(in1 == in2); // true System.out.println(in5 == in6); // false System.out.println(in1 == in3); // false System.out.println(in3 == in4); // false
在 Boxing Conversion 部分的Java语言规范(JLS)规定如下:
如果一个变量 p 的值属于:-128至127之间的整数(§3.10.1),true 和 false的布尔值 (§3.10.3),’u0000′ 至 ‘u007f’ 之间的字符(§3.10.4)中时,将 p 包装成 a 和 b 两个对象时,可以直接使用 a == b 判断 a 和 b 的值是否相等。
所有整数类型的类都有类似的缓存机制:
- 有 ByteCache 用于缓存 Byte 对象
- 有 ShortCache 用于缓存 Short 对象
- 有 LongCache 用于缓存 Long 对象
Byte,Short,Long 的缓存池范围默认都是: -128 到 127。可以看出,Byte的所有值都在缓存区中,用它生成的相同值对象都是相等的。
所有整型(Byte,Short,Long)的比较规律与Integer是一样的。
同时Character 对象也有CharacterCache 缓存 池,范围是 0 到 127。
除了 Integer 可以通过参数改变范围外,其它的都不行。