java基础数据类型自动装箱拆箱
一、定义:
public class test {
public static void main(String[] args) {
Integer a = 3;//装箱
int b = a;//拆箱
}
}
查看Integer的源码,可知:
基础类型的包装类,装箱,实际调用的是包装类的valueof方法;
拆箱,调用的是包装类的:xxxValue方法;
比如对于Integer,装箱:Integer.valueOf(int i);拆箱:Integer.intValue()。
二、运用举例及坑:
1、运用举例代码:
public class TestAutoBoxing {
/**
* 测试类演示基础类型的自动装箱和拆箱,及比较规则
* @author cdzhujun
*/
public static void main(String[] args) {
/**
* 在-128~127 之内的数,如果已经有了,则会缓存,支持复用 类似类型还有:Short/Character/Long/Byte
* 取值范围: Integer,Byte,Short,Long:[-128,127] Character:[0,127]
* Float,Double:没有缓存,每次都new一个新的 Boolean:只有两个固定值,只要值一样就相等
*/
System.out.println("############################");
// 在-128~127 之外的数
Integer ii1 = 200;
Integer ii2 = 200;
System.out.println("ii1==ii2: " + (ii1 == ii2));// false
// 在-128~127 之内的数
Integer ii3 = 100;
Integer ii4 = 100;
System.out.println("i3==i4: " + (ii3 == ii4));// true
System.out.println("—————————");
Double d1 = 100.0;
Double d2 = 100.0;
Double d3 = 200.0;
Double d4 = 200.0;
System.out.println(d1 == d2); // false
System.out.println(d3 == d4); // false
System.out.println("—————————");
Boolean b1 = false;
Boolean b2 = false;
Boolean b3 = true;
Boolean b4 = true;
System.out.println(b1 == b2);// true
System.out.println(b3 == b4);// true
System.out.println("—————————");
/**
* ==比较:
* 都为基础类型时,比较的是值;都为包装类时,按缓存规则比较;基础类和包装类比较,包装类会自动拆箱
* new就不说了,每次new,都在堆内存中新建一个对象
*/
System.out.println("############################");
// Example 1: 都为基础类型时,比较的是值
int i1 = 1;
int i2 = 1;
System.out.println("i1==i2 : " + (i1 == i2)); // true
// Example 2: 都为包装类时,按缓存规则比较
Integer obj1 = 1;
Integer obj2 = 1;
System.out.println("obj1 == obj2 : " + (obj1 == obj2)); // true
// Example 3: 基础类和包装类比较,包装类会自动拆箱
Integer num1 = 1;
int num2 = 1;
System.out.println("num1 == num2 : " + (num1 == num2)); // true
// Example 4: new就不说了,每次new,都在堆内存中新建一个对象
Integer one = new Integer(1);
Integer anotherOne = new Integer(1);
System.out.println("one == anotherOne : " + (one == anotherOne)); // false
// Example 5: 一个是包装类,一个是new出来的,也相当于两个new
System.out.println(num1 == one); // false
/**
* ==的特殊场景:
* 1、如果==号比较的其中一个为表达式(以+、-、*、/、>、<运算符运算的,包装类先拆包参与运算
* 2、当 ==运算符的两个操作数都是包装器类型的引用,则是比较指向的是否是同一个对象;
* 而如果其中有一个操作数是表达式(即包含算术运算),则比较的是数值(即会触发自动拆箱的过程)。
*/
System.out.println("############################");
Integer num111 = 100;
int num222 = 100;
Long num333 = 200L;
long numm3 = 100L;
Integer numm1 = 200;
//num111先拆箱参与运算,num111+num222运算后为int类型,然后在装箱变为Integer
//由于右侧的操作是包含表达式,故最终num333和(num111 + num222)计算的结果会自动拆箱,变成long与int类型
//long/int基础类型是可以进行==比较的,比较的仅仅是值,故最终结果返回true
System.out.println(num333 == (num111 + num222)); //true
System.out.println(num222 == numm3); //true
//System.out.println(num333 == numm1);//这样写是不行的,应为类型不匹配
/**
* 包装类的equals():类型相同,且变量的值相等,才会最终返回true
* 注意:包装类的equals()方法重写了Object类的相同方法;
* 而String、Date类亦重写了Object类equals(),只是实现不一样(不在这里讨论)
*/
System.out.println("############################");
Integer num11 = 100;
int num22 = 100;
Long num4 = 200L;
System.out.println(num11.equals(num22)); //true
System.out.println(num4.equals(num11 + num22)); //false,因为equals不拆箱,因Long与Integer类型不匹配
System.out.println(num4 == (num11 + num22)); // true,有操作符,+计算结果会拆箱
}
}
2、坑:Integer类型可以为null,int类型不能为null。
Integer i1=null;
int i2=i1;
这两行代码是完全合法的,完全能够通过编译的,但是在运行时,就会抛出空指针异常,因为int类型不能为null。
所以:在自动拆箱时,要保证包装类的值不能为null。
三、自动装箱拆箱的优点及弊端:
1、优点:
省事, 简化代码。自动把基础类型和包装类互转。
节约内存。如上面的例子,在数字范围比较小时,可复用类的对象( [-128,127] )。
2、弊端:在一个循环中进行自动装箱操作的情况,如下面的例子就会创建多余的对象,影响程序的性能。
Integer sum = 0;
for(int i=1000; i<5000; i++){
sum+=i;
}
内部实际为:
sum = sum.intValue() + i;
Integer sum = new Integer(result);
new了很多个对象出来,但没实际用处,故会增加外内存开销,影响性能。
四、基本类型与包装类型的异同
1、在Java中,一切皆对象,但八大基本类型(char,byte,int,double,float,short,long,boolean)却不是对象。
2、声明方式的不同,基本类型无需通过new关键字来创建,而封装类型需new关键字。
3、存储方式及位置的不同,基本类型是直接存储变量的值保存在栈中能高效的存取,封装类型需要通过引用指向实例,具体的实例保存在堆中。
4、初始值的不同,封装类型的初始值为null,基本类型的的初始值视具体的类型而定,比如int类型的初始值为0(整数:包括int,short,byte,long ,初始值为0),boolean类型为false,浮点型:float,double ,初始值为0.0,字符:char ,初始值为空格,即'' ",如果输出,在Console上是看不到效果的。
5、使用方式的不同,比如与集合类合作使用时只能使用包装类型。