Java--装箱和拆箱详解

目录
  • 装箱
  • 拆箱
  • ==
  • null
  • 总结

装箱

八大基本类型都有一个与之对应的类:

基本类型
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

除了后两个Character和Boolean类是Object派生类外,其余六个是继承自Number类。

这些类称为包装器(wrapper),一旦构造了对象包装器,就不允许更改包装器在其中的值同时,对象包装器类还是final修饰,所以也不能定义继承它们的子类。

有时候需要将基本类型转换为对象,比如定义一个整数型列表,尖括号中的类型参数不允许是基本类型,即不允许写成ArrayList<int>,这时就需要用到Integer包装器类,可以声明一个Integer对象的数组列表ArrayList<Integer>。

而且为了便于添加int类型的元素到ArrayList<Integer>中,下面语句会自动装箱

list.add(8);

即自动地变换成:

list.add(Integer.valueof(8));

再比如Integer num=8;也是自动装箱,会转换成Integer num=Integer.valueOf(8);,即将基本类型赋值给相应的类时,会触发自动装箱。

但是由于装箱操作会创建对象,频繁的装箱操作会消耗许多内存,影响性能,所以应该尽量避免装箱。

拆箱

同样的,将类转换为对应的基本类型的过程就称为拆箱,如上面的Integer类型变量num,int num2=num;就会触发自动拆箱,自动地转换为int num2=num.intValue();

还有在算术表达式中也能够自动地装箱和拆箱,例如:

Integer n=6;
n++;
n-=2;

编译器将自动地插入一条对象拆箱的指令,然后进行自增计算,最后再将结果装箱。

注意装箱和拆箱是编译器认可的,而不是虚拟机,编译器在生成类的字节码时,插入必要的方法调用,而虚拟机只是执行这些字节码。

使用数值对象包装器可以将某些基本方法防止在包装器中,例如parseInt()方法将一个数字字符串转换成数值,parseInt()是一个静态方法,与这里的Integer类对象没有任何关系,只是Integer类是放置这个方法的一个好地方罢了。

而我们的拆箱装箱无非是自动的调用了放置在类里面的方法如intValue()valueOf()等。

==

首先看看Integer.valueOf()函数的源码,就知道==的坑了。

public static Integer valueOf(int i) {
	return  i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];
	}

它会首先判断 i i i的大小:如果 i > = 128 ∣ ∣ i < − 128 i>=128||i<-128 i>=128∣∣i<−128,就创建一个Integer对象,否则执行SMALL_VALUES[i + 128],再定位到SMALL_VALUES:

private static final Integer[] SMALL_VALUES = new Integer[256];

它是一个已经创建好的静态的Integer数组对象,也就是说 i i i在 [ − 128 , 128 ) [-128,128) [−128,128)的范围内时,不会创建新的对象,否则会创建新的对象,这也就是装箱为什么创建对象,从而消耗内存。

(插播反爬信息 )博主CSDN地址:https://wzlodq.blog.csdn.net/

比如以下==判断:

    public static void main(String[] args) {
        Integer i1=88;
        Integer i2=88;
        Integer i3=666;
        Integer i4=666;
        System.out.println(i1==i2);//true
        System.out.println(i3==i4);//false
    }

==是判断两个对象的内存地址是不是相等,显然88在区间(-128,128)内,直接指向同一个创建好的数组,而666则会重新创建新对象。

同样的boolean、byte、char<128;shot、int介于[-128,127]间时,会包装到固定的对象中,比较结果一定成立,否则会创建新的对象,比较结果不成立。

这样我们就能知道,混用时是自动拆箱还是自动装箱了,如:

Integer n=666;
int m=666;
System.out.println(n==m);//true

如果是n自动拆箱,则指向常量池同一地址,则结果为true;如果是m自动装箱,不在区间范围内,创建新对象,则结果为false。答案是n自动拆箱。

再如:

Integer x=100;
int y=200;
Long z=300l;
System.out.println(x+y==z);//true
System.out.println(z.equals(x+y));//false

如果x、y、z自动拆箱则指向常量池同一地址,==结果true;如果x、y拆箱后装箱成Long,不在区间范围内,创建新对象,= =结果是false。答案是会拆箱。

那equals为什么输出false?因为equals除了比较值相同外,还会比较数据类型,显然两者拆箱后分别是int和long型,故判断为false。

null

由于包装类的引用可以为null,所以自动装箱时可能会抛出一个NullPointerException异常,如:

Integer n=null;
int m=n;

另外如果在一个条件表达式中混合使用Integer和Double类型,Integer值会拆箱,提升为Double,再装箱为Double:

Integer n=6;
Double m=8.0;
System.out.println(true?n:m); //6.0

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 详解Java 自动装箱与自动拆箱

    包装器 有些时候,我们需要把类似于int,double这样的基本数据类型转成对象,于是设计者就给每一个基本数据类型都配置了一个对应的类,这些类被称为包装器. 包装器整体来说分为四大种: Number,Number类派生出了Integer,Double,Long,Float,Short,Byte这六个小类分别代表了int,double,long,float,short,byte这六种基本数据类型. Character,对应的基本数据类型是char. Void,对应的是关键字void,这个类我们会经

  • 深入理解Java中的装箱和拆箱

    前言 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来一些看一下装箱和拆箱中的若干问题.本文先讲述装箱和拆箱最基本的东西,再来看一下面试笔试中经常遇到的与装箱.拆箱相关的问题. 若有不正之处,请谅解和批评指正,不胜感激. 一.什么是装箱?什么是拆箱? 在前面的文章中提到,Java为每种基本数据类型都提供了对应的包装器类型,至于为什么会为每种基本数据类型提供包装器类型在此不进行阐述,有兴趣的朋友可以查阅相关资料.在Java SE5之前,如果要生成一个数值为10的Integer对象,

  • Java中自动装箱、拆箱引起的耗时详解

    什么是自动装箱,拆箱 先抛出定义,Java中基础数据类型与它们的包装类进行运算时,编译器会自动帮我们进行转换,转换过程对程序员是透明的,这就是装箱和拆箱,装箱和拆箱可以让我们的代码更简洁易懂 耗时问题 在说 Java 的自动装箱和自动拆箱之前,我们先看一个例子. 这个错误我在项目中犯过(尴尬),拿出来共勉! private static long getCounterResult() { Long sum = 0L; final int length = Integer.MAX_VALUE; f

  • Java基础详解之包装类的装箱拆箱

    一.包装类 概念: Java提供了两个类型系统,基本数据类型和引用数据类型,使用基本数据类型在于效率,然而很多情况下回创建对象使用,因为对象能做更多的功能. 所以可以使用一个类,把基本数据类型包装起来,在类中定义一些方法,这就叫做包装类.我们可以用这种方法来操作这些数据类型 基本类型 对应包装类(位于java.lang中) byte Byte short Short int Integer long Long float Float double Double char Character bo

  • Java Integer及int装箱拆箱对比

    示例代码: class BoxIntInteger { public static void main(String[] args) { Integer a = new Integer(10111); int b = 10111; boolean equal1 = a == b; boolean equal2 = a.equals(b); System.out.println(equal1); System.out.println(equal2); } } 反编译字节码: public stat

  • Java 装箱与拆箱详解及实例代码

    Java 装箱与拆箱详解 前言: 要理解装箱和拆箱的概念,就要理解Java数据类型 装箱:把基本类型用它们相应的引用类型包装起来,使其具有对象的性质.int包装成Integer.float包装成Float 拆箱:和装箱相反,将引用类型的对象简化成值类型的数据 Integer a = 100; 这是自动装箱 (编译器调用的是static Integer valueOf(int i)) int b = new Integer(100); 这是自动拆箱 看下面一段代码 m1 public class

  • 如何通过源码了解Java的自动装箱拆箱详解

    目录 什么叫装箱 & 拆箱? 首先看一段代码 装箱(valueOf()) 为什么要有[-128,127]的缓存? 为什么是[-128,127]? 自动装箱带来的性能问题 小总结 拆箱(intValue) 补充:自动装箱.拆箱总是会发生吗? 总结 什么叫装箱 & 拆箱? 将int基本类型转换为Integer包装类型的过程叫做装箱,反之叫拆箱. 首先看一段代码 public static void main(String[] args) { Integer a = 127, b = 127;

  • Java--装箱和拆箱详解

    目录 装箱 拆箱 == null 总结 装箱 八大基本类型都有一个与之对应的类: 基本类型 类 byte Byte short Short int Integer long Long float Float double Double char Character boolean Boolean 除了后两个Character和Boolean类是Object派生类外,其余六个是继承自Number类. 这些类称为包装器(wrapper),一旦构造了对象包装器,就不允许更改包装器在其中的值同时,对象包

  • 详解Java 自动装箱与拆箱的实现原理

    什么是自动装箱和拆箱 自动装箱就是Java自动将原始类型值转换成对应的对象,比如将int的变量转换成Integer对象,这个过程叫做装箱,反之将Integer对象转换成int类型值,这个过程叫做拆箱.因为这里的装箱和拆箱是自动进行的非人为转换,所以就称作为自动装箱和拆箱.原始类型byte, short, char, int, long, float, double 和 boolean 对应的封装类为Byte, Short, Character, Integer, Long, Float, Dou

  • 基于数据类型转换(装箱与拆箱)与常量详解

    隐式转换[自动类型转换]: 两种类型要兼容,原类型值域要小于目标类型值域,可以简单的理解为由小转大. public class Test { private void Start() { int a = 10; float b = a;//int 类型隐式转换为 float 类型 } } 显示转换[强制类型转换]: 两种类型要兼容,原类型值域要大于目标类型值域,可以简单的理解为由大转小. [缺点]:1.数据溢出.2.精度丢失. 数值类型之间的转换. public class Test { pri

  • C#装箱和拆箱原理详解

    .NET包含一个特殊的Object类,可以接受任意的数据类型的值,当所传递或所赋值的类型不是一个特定的数据类型时,object类就提供了一种传递参数和赋值的通用方法.赋给object的值必须作为引用类型,并存放砸托管堆中. 装箱: int age = 24; object refAge= age; 可以看的出,第一条语句创建一个变量age,并将值放在托管栈中: 第二条语句将age的值赋给引用类型.它将值24放在托管堆中. 这个值类型包装为引用类型的过程,称为装箱. 拆箱: 相反,将引用类型转换为

  • 再议C#中的装箱与拆箱的问题详解

    上一篇写了一下装箱拆箱的定义和IL分析,这一篇我们看下使用泛型和不使用泛型引发装箱拆箱的情况1.使用非泛型集合时引发的装箱和拆箱操作 看下面的一段代码: 复制代码 代码如下: var array = new ArrayList();array.Add(1);array.Add(2); foreach (int value in array){Console.WriteLine("value is {0}",value);} 代码声明了一个ArrayList对象,向ArrayList中添

  • 解析C#中的装箱与拆箱的详解

    装箱和拆箱是值类型和引用类型之间相互转换是要执行的操作. 1. 装箱在值类型向引用类型转换时发生2. 拆箱在引用类型向值类型转换时发生光上述两句话不难理解,但是往深处了解,就需要一些篇幅来解释了.我们先看装箱时都会发生什么事情,下面是一行最简单的装箱代码 复制代码 代码如下: object obj = 1; 这行语句将整型常量1赋给object类型的变量obj: 众所周知常量1是值类型,值类型是要放在栈上的,而object是引用类型,它需要放在堆上:要把值类型放在堆上就需要执行一次装箱操作.这行

  • Java中的装箱和拆箱深入理解

    自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来一些看一下装箱和拆箱中的若干问题.本文先讲述装箱和拆箱最基本的东西,再来看一下面试笔试中经常遇到的与装箱.拆箱相关的问题. 一.什么是装箱?什么是拆箱? 在前面的文章中提到,Java为每种基本数据类型都提供了对应的包装器类型,至于为什么会为每种基本数据类型提供包装器类型在此不进行阐述,有兴趣的朋友可以查阅相关资料.在Java SE5之前,如果要生成一个数值为10的Integer对象,必须这样进行: 复制代码 代码如下: Intege

随机推荐