转载请注明原文地址:http://www.javashuo.com/article/p-qkunbogr-ee.htmlhtml
咱们知道,Java有8大基本数据类型,4整2浮1符1布。java
咱们在实际开发中,除了使用到数据的值以外,还会涉及到对数据的操做。根据“面向对象”编程的思想,这些常见的操做被抽象成方法,封装到了一个类中,一个基本数据类型对应一个这样的类,这些类统称为“包装类”。编程
8大基本类型 分别对应 8个包装类,再加上两个用于高精度运算的包装类,共有10大包装类。分别为:数组
Byte:对应 byte 类型缓存
Short:对应 short类型jvm
Integer:对应 int类型ide
Long:对应 long类型函数
Float:对应 float类型工具
Double:对应 double类型性能
Character:对应 char类型
Boolean:对应 boolean类型
BigInteger:支持任意精度[长度]的整数运算。
BigDecmail:支持任意精度的浮点数运算,主要用于金额计算。
包装类的好处:它提供了一系列操做本类型数据的方法,能够为咱们在开发过程当中操做8大基本类型数据提供充足的“工具”。
一、装箱
把基本数据类型转换成包装类的过程就是打包装,英文名boxing,翻译为装箱。
二、拆箱
反之,把包装类转换成基本数据类型的过程就是拆包装,英文对应于unboxing,中文翻译为拆箱。
三、自动拆装箱
自动装箱: 就是将基本数据类型自动转换成对应的包装类。
自动拆箱:就是将包装类自动转换成对应的基本数据类型。
四、自动拆装箱的发生场景
1)自动拆装箱的过程主要发生在赋值操做上:将一个基本数据类型的值符给包装类变量,则进行自动装箱操做;将一个包装类变量的值赋给基本数据类型变量,则发生自动拆箱操做。
2)将基本数据类型放入集合类时:Java中的集合类只能接收对象类型,当咱们把基本数据类型放入集合类中的时候,会进行自动装箱成对应的包装类对象后再放入。
3)基本数据变量与包装类变量进行运算操做时:基本数据变量与包装类变量进行比较运算、数学运算、三目运算时,会自动拆箱成基本类型再进行运算。
4)函数返回值自动拆装箱:当函数定义时,指定了函数返回值是包装类,则return 一个基本数据类型值时,就会自动装箱;若是定义的函数返回值是基本数据类型时,return一个包装类对象会自动拆箱。
一、包装对象的数值比较,不能简单的使用==
,虽然-128到127之间的数字能够[下文中解释],可是这个范围以外仍是须要使用equals
比较。【== 比较的是地址,equals比较的是值】
二、因为自动拆箱,若是包装类对象为null,那么自动拆箱时就有可能抛出NPE[null pointer exception]。
三、若是在一个for循环中有大量拆装箱操做,会浪费不少资源。
详情可参阅:Java中整型的缓存机制 这篇文章。
首先看个例子:
package com.javapapers.java;public class JavaIntegerCache { public static void main(String... strings) { Integer integer1 = 3; //整数3自动装箱 Integer integer2 = 3; //整数3自动装箱 if (integer1 == integer2) //两个自动装箱后对象比较 System.out.println("integer1 == integer2"); else System.out.println("integer1 != integer2"); Integer integer3 = 300;//整数300自动装箱 Integer integer4 = 300;//整数300自动装箱 if (integer3 == integer4)//两个自动装箱后对象比较 System.out.println("integer3 == integer4"); else System.out.println("integer3 != integer4"); }}
上面的代码输出的结果是:
integer1 == integer2
integer3 != integer4
也就是说:整数3自动装箱后赋值给a、b两个引用变量,这两个引用指向的是同一个对象。
可是整数300自动装箱后赋值给c、d两个引用变量,这两个引用指向的是不一样对象。
那么问题来了——都是自动装箱,为何不一样数值自动装箱的结果不同呢?——这是因为Integer的缓存机制致使的。
在实际开发过程当中,会常常在不经意间就触发了自动拆装箱机制。咱们知道,自动装箱会建立一个包装类对象,一套程序跑下来,会生成多少个这样的对象?那开销得多大啊。
所以,出于节省内存和提升性能的目的,从Java5开始,为咱们提供了Integer的缓存机制。
这个缓存机制是怎么工做的呢?咱们来看一下Integer类的取值方法——valueOf的源码。
/** * Returns an {@code Integer} instance representing the specified * {@code int} value. If a new {@code Integer} instance is not * required, this method should generally be used in preference to * the constructor {@link #Integer(int)}, as this method is likely * to yield significantly better space and time performance by * caching frequently requested values. * * This method will always cache values in the range -128 to 127, * inclusive, and may cache other values outside of this range. * * @param i an {@code int} value. * @return an {@code Integer} instance representing {@code i}. * @since 1.5 */ public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) //先判断整数值为是否处于IntegerCache.low~IntegerCache.high之间的缓存值 return IntegerCache.cache[i + (-IntegerCache.low)]; //是的话,则从缓存数组中取对应的包装类对象之间返回 return new Integer(i);//否,则建立一个新的包装类对象返回 }
从代码中能够看出,自动装箱时,建立对象以前先从IntegerCache.cache中寻找,若是没找到才使用new新建对象。
IntegerCache 类源码
/** * 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=} 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; //默承认缓存的最小值是 -128 static final int high; //可缓存的最大值 static final Integer cache[]; //缓存数组 static { // high value may be configured by property 可缓存最大值可经过jvm参数指定 int h = 127; //默承认缓存最大值为127 String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); //从JVM参数中获取可缓存最大值配置 if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127);//将配置值与127之间取较大值,即:可缓存值最小为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;//断言:可缓存最大值必须大于等于127 } private IntegerCache() {} }
从上面能够得知,Integer缓存数组中保存了 -128~h(h>=127) 的值的包装类对象,其中h值能够经过JVM参数 -XX:AutoBoxCacheMax=size
修改【这也是JVM调优的一个经常使用配置项】。
至于最小范围 -128~127 之间,是由于这个范围的数字是最被普遍使用的。
IntegerCache是Integer类中定义的一个private static
的内部类,所以在程序中,第一次使用Integer对象的时候会须要必定的额外时间来初始化这个缓存。
ByteCache用于缓存Byte对象:固定范围: -128 到 127,不能更改。
ShortCache用于缓存Short对象:固定范围: -128 到 127,不能更改。
LongCache用于缓存Long对象:固定范围: -128 到 127,不能更改。
CharacterCache用于缓存Character对象:固定范围: 0 到 127,不能更改。
举个例子:
若是一个变量p的值是: -128至127之间的整数 true 和 false的布尔值 ‘\u0000’至 ‘\u007f’之间的字符 之间时,将p自动装箱成a和b两个对象,能够直接使用a==b判断a和b的值是否相等。