关键词:
装箱与拆箱
什么是装箱与拆箱
描述
语言描述,装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。
代码描述就是:
Integer integer = 100; //自动装箱
int i = integer; //自动拆箱
基本技术类型对应的包装器类型表:
数据类型 | 包装器类型 |
---|---|
int(4字节) | Integer |
byte(1字节) | Byte |
short(2字节) | Short |
long(8字节) | Long |
float(4字节) | Float |
double(8字节) | Double |
char(2字节) | Character |
boolean(未定) | Boolean |
如何实现装箱与拆箱
装箱与拆箱的代码
public class IntegerAndInt
public static void main(String[] args)
// TODO Auto-generated method stub
Integer integer = 100; //自动装箱
int i = integer; //自动拆箱
反编译class文件
从反编译得到的字节码内容可以看出,在装箱的时候自动调用了Integer的valueOf(int)方法。而在拆箱的时候自动调用的是Integer的intValue方法。
因此,装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的xxxValue方法实现的。
valueOf方法
public static Integer valueOf(int i)
return i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];
首先判断数值大小,如果数值大于等于128或者小于-128,则创建一个Integer对象返回,否则,则返回SMALL_VALUES的i+128的数值。
接着,查看以下Integer的构造函数:
private final int value;
public Integer(int value)
this.value = value;
public Integer(String string) throws NumberFormatException
this(parseInt(string));
Integer定义了一个value变量,创建一个Integer对象时,就会给这个变量初始化。第二个传入的是一个String变量,它会先把它转换成一个int值,然后进行初始化。
再看一下SMALL_VALUES[i+128]是什么:
private static final Integer[] SMALL_VALUES = new Integer[256];
SMALL_VALUES是一个静态的Integer数组对象,也就是说valueOf返回的都是一个Integer对象。
通过分析可以看到装箱的过程会创建对应的对象,这个会消耗内存,所以装箱的过程会增加内存的消耗,影响性能。
initValue方法
@Override
public int intValue()
return value;
intValue方法直接返回了value值。
装箱与拆箱需要注意的一些问题
例子一
public class Main
public static void main(String[] args)
Integer i1 = 66, i2 = 66, i3 = 166, i4 = 166;
System.out.println(i1 == i2);//true
System.out.println(i3 == i4);//false
看上面的代码可以发现,两个比较的结果不相同,再结合上面的装箱原理,128~-127的装箱是直接返回的SMALL_VALUES数组中存储的值,所以i1和i2的装箱结果返回的是同一个变量,所以是相等的,而i3和i4是返回的新创建的变量,两个变量是不同的,所以不相等。
例子二
Integer a = new Integer(6);
Integer b = 6; // 将6自动装箱成Integer类型
int c = 6;
System.out.println(a == b); // false 两个引用没有引用同一对象
System.out.println(a == c); // true a自动拆箱成int类型再和c比较
a是一个创建的Integer对象,而b是自动装箱,是SMALL_VALUES数组中存储的值,所以a和b是不同的对象,不相等,而c是int类型的值,a与c相比是会先拆箱为int类型的6,两个6数值相比,故相等。
例子三
Integer i1 = new Integer(6);
Integer i2 = 6;
System.out.println("i1.equals(i2):"+(i1.equals(i2))); //true
会发现同样的对象,==与equals的结果是不同,先看一下equals源码:
@Override
public boolean equals(Object o)
return (o instanceof Integer) && (((Integer) o).value == value);
发现equals方法是比较value值相同的,比较的内容的本身。
例子四
Integer num1 = 100;
int num2 = 100;
Long num3 = 200L;
System.out.println(num1+num2); //200
System.out.println(num3 == (num1+num2)); //true
System.out.println(num3.equals(num1+num2)); //false
System.out.println(num3 == (num1+num2)); //true
当一个基本类型数据域封装类进行==、+、-、*、/运算时,会将封装类进行拆箱,对基础数据类型进行运算。
而num3.equals(num1+num2)为false的原因是,num1+num2的类型不是Long,所以为false。
Long的equals方法:
@Override
public boolean equals(Object o)
return (o instanceof Long) && (((Long) o).value == value);
而(num3 (num1+num2))为true,当运算符的两个操作数都是包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。
例子五
Integer integer=null;
int i=integer;
上面的代码可以通过编译,但是在运行时,就会抛出空指针异常。integer是Integer类型的对爱选哪个,可以指向null,但是对integer进行拆箱的时候,就是对一个null对象调用valueOf方发,所以会抛出空指针异常。
注意
Integer、Short、Byte、Charater、Long这几个类的valueOf方法的实现是类似的,Double和Float的valueOf方法的实现是类似的,是没有想Integer一样的SMALL_VALUE数组的。
Double的valueOf方法:
public static Double valueOf(double d)
return new Double(d);
Float的valueOf方法:
public static Float valueOf(String s) throws NumberFormatException
return new Float(FloatingDecimal.getThreadLocalInstance().readJavaFormatString(s).floatValue());
还有,Boolean的valueOf方法:
public static Boolean valueOf(boolean b)
return (b ? TRUE : FALSE);
所以不管对象是不是同一个,只要对象的值时相同的,就是相等的。
5.总结
Java通过自动装箱和拆箱的机制,节省了部分内存开销和创建对象的开销(Integer的128~-127常用值节省开支),提高了效率同时简化了代码,不用每次需要程序员转换类型。在比较数值相等时,尽量使用equals()方法。
参考文章
https://www.cnblogs.com/wang-yaz/p/8516151.html 详解Java的自动装箱与拆箱(Autoboxing and unboxing)
https://www.cnblogs.com/dolphin0520/p/3780005.html 深入剖析Java中的装箱和拆箱
装箱与拆箱(代码片段)
在C#中,装箱和拆箱在值类型和引用类型的类型转换时发生。将值类型转换为引用类型通过装箱机制;将引用类型装换为值类型伴随着拆箱。将值类型装箱:在托管堆中分配内存将值类型字段复制到新分配的堆内存返回对象地址... 查看详情
装箱与拆箱(代码片段)
装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。packagecom.lv.pm;publicclassTest4publicstaticvoidmain(String[]args)//基本数据类型是不是Object的子类?//装箱拆箱//给8种基本数据类型,做一个... 查看详情
c#基础:理解装箱与拆箱(代码片段)
...型的变量表示为另一种类型的变量。为此,C#提供了装箱和拆箱的机制。1理解装箱简单地说ÿ 查看详情
[019]c#基础:理解装箱与拆箱(代码片段)
...型的变量表示为另一种类型的变量。为此,C#提供了装箱和拆箱的机制。1理解装箱简单地说ÿ 查看详情
装箱与拆箱(代码片段)
装箱:将基本类型用他们对应的引用类型包装起来拆箱:将包装类型转换为基本类型自动拆装箱:Integer i =10; //自动装箱 反编译后代码:integeri=Integer.valueOf(10);int b= i; //自动... 查看详情
java基础--字符串类(stringstringbufferstringbuilder)自动装箱与拆箱(代码片段)
...全性2.3性能2.4对于三者使用的建议2.5面试题的回答3.自动装箱与拆箱1.预备知识所有不可变类都是线程安全的,线程安全的类不一定是不可变类,如StringBuffer是可变类,靠锁实现线程安全。StringBuffer方法上都加 查看详情
java自动装箱与拆箱
...语法,简化了基本数据类型对象的使用,我们称之为自动装箱(autoboxing)与拆箱(unboxing)。之前的代码可以简化为Integeri=7;。Java提供的自动装箱盒拆箱,是在编译 查看详情
自动装箱与拆箱(代码片段)
...wrapper)。基本数据类型转换为对应的对象类型的过程叫装箱,把包装器转换为基本数据类型类型的过程叫拆箱。注意:↓Integerx=3;Integery=3;System.out.println(x==y);//trueSystem.out.println(x.equals(y));//trueIntegera=128;Integerb=128;System.out.println(a==b... 查看详情
了解java的自动装箱与拆箱
一.简单来说,装箱就是自动将基本数据类型转换成包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。 //自动装箱 Integertotal=99; //自动拆箱 inttotalprim=total; 需要装箱拆箱的类型... 查看详情
自动装箱与拆箱
...型都提供了对应的包装器类型从JavaSE5开始就提供了自动装箱的特性,如果要生成一个数值为10的Integer对象,只需要这样就可以了:Integeri=10;这个过程中会自动根据数值创建对应的Integer对象,这就是装箱。实际上,执行上面那句... 查看详情
装箱与拆箱
boxing,unboxing.装箱,值对象到引用对象的转换,会在堆上分配空间,栈到堆的拷贝,返回新的对象地址。拆箱,获取装箱对象的的部分字段地址,然后从托管堆到线程堆栈进行拷贝。拆箱需要判断运行时类型信息,suppose会费时一... 查看详情
装箱与拆箱
把值类型转换为引用类型,叫装箱。把引用类型转换为值类型,称之为拆箱。看例子:1intn=10;2strings=n.ToString();//不是装箱345objecto=10;//是装箱67Console.ReadKey();ViewCode1.定义。2.转换的两个类型能兼容另一个类型。(是直系的继承,而... 查看详情
装箱与拆箱的概念
装箱与拆箱的概念:简单的来讲:装箱:就是将值类型的数据打包到引用类型的实例中比如将int类型的值123赋给object对象o inti=123;objecto=(object)i; ... 查看详情
详解java中的自动装箱与拆箱,5000+字,看了不懂你打我(代码片段)
什么是自动装箱拆箱?很简单,下面两句代码就可以看到装箱和拆箱过程//自动装箱Integertotal=99;//自动拆箱inttotalprim=total;简单一点说,装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包... 查看详情
装箱与拆箱的整理
1、概念:装箱是将值类型装换成引用类型的过程;拆箱就是将引用类型转换成值类型的过程; 2、利用装箱和拆箱功能,通过允许值类型的任何值与Object类型的值进行相互转换,将引用类型与值类型连接起来。 3、注... 查看详情
日期类时间类,日期时间类,单例模式,装箱与拆箱,数字类随机数,bigdecimal总结(代码片段)
1.日期类,时间类,日期时间类初步日期使用方法及格式转换方法(旧方法):格式://MonJul3011:26:05CST2018 年月日时分秒 CST代表北京时间获取当前毫秒Datedate=newDate(... 查看详情
java自动装箱与拆箱
什么是自动装箱拆箱基本数据类型的自动装箱(autoboxing)、拆箱(unboxing)是自J2SE5.0开始提供的功能。 一般我们要创建一个类的对象实例的时候,我们会这样: Classa=newClass(parameter); 当我们创建一个Integer对象时,却可以这... 查看详情
装箱与拆箱
一、装箱机制:1,在托管堆中分配内存。分配的内存量是值类型各字段所需的内存量,还要加上托管堆中所有对象都有的两个额外成员(类型对象指针和同步块索引)所需的内存量2,值类型字段复制到新分配的堆内存3,返回对... 查看详情