java装箱与拆箱的深入理解

Java有一个类型系统有两个部分组成,包含基本类型(byte、char、int、short、long、float、double、boolean)和引用类型。而基本类型则对应着各自的引用类型,称为装箱的基本类型。而引用类型对应着各自的基本类型,称为拆箱的基本类型。对应的类型为:(Byte、Character、Integer、Short、Long、Float、Double、Boolean)

下面一具体例子来说明装箱与拆箱

//java 1.5之前创建一个Integer对象
Integer i = new Integer(10);
//java 1.5之后有了装箱的特性,直接用下列方式生成一个Integer对象
//在这个过程中会将int 类型的10自动装箱成为Integer类型
Integer i = 10;
//拆箱 输出的值为20,这个过程中,会先将Integer类型的j自动拆箱为基本类型的10,最后完成运算
Integer j = new Integer(10);
int k = 10;
System.out.print(j+k);

下面来说说基本数据类型与其对应的引用类型的区别:

  1. 基本类型只有值,而装箱基本类型既具有值也具有它们对象的同一性(就是两个装箱的基本类型具有相同的值和不同的同一性(对象不一样))
  2. 基本类型只有功能完备的值,而每个装箱类型不仅具有完备的值还具有所有功能值之外的null。
  3. 基本类型通常比装箱基本类型更节省时间和空间。

下面来举一个《Effective java中》的一个例子进行分析

Comparator<Integer> comparator = new Comparator<Integer>()
{
    public int compareTo(Integer first,Integer second)
    {
        return first > second ? 1:first == second ? 0 : -1;
    }

}
//这两个Integer实例都表示相同的值42
Integer a = new Integer(42);
Integer b = new Integer(42);
int c = comparator.compareTo(a,b);
//返回值多少 0 ? 但实际结果却是-1,难道 42 < 42 ?

下面就来解释上面例子的原因:
首先执行 a>b,两个Integer都自动拆箱为42,不成立,则执行 a==b,乍一看,没什么问题,42==42没问题啊,但实际上这是违反了了装箱的同一性,因为a和b都是引用类型,根据上述两个装箱类型具有相同的值和不同的同一性,只是两个对象的比较,即这两个对象是不同对象,所对应的内存也不一样,a!=b。所有正确答案应该是 -1。

现在来说说装箱和拆箱是怎么实现的:

public static void main(String[] args){
  Integer i = 10;
  int j = 10;
  System.out.print("i+j = "+(i+j));
}

打印结果为:

Paste_Image.png

反编译class文件得到:

Paste_Image.png

第一行是装箱过程,查看源码实际是调用了Integer.valueOf(int)方法返回一个Integer实例
第三行进行加法运算的时候是拆箱过程,将Integer实例i拆箱为int型,然后进行加法运算,实际是调用了Integer.intValue()方法返回一个int型数据。

关于装箱与拆箱大致的都讲的差不多了。下面举几个面试中关于装箱与拆箱会问到的例子:

public class Main 
{
   public static void main(String[] args) 
  {
      Integer i1 = 100;
      Integer i2 = 100;
      Integer i3 = 200;
      Integer i4 = 200;

      System.out.println(i1==i2); //返回true
      System.out.println(i3==i4); //返回false
 }
}

下面来解释下这个原因

//这是装箱的源码
public static Integer valueOf(int i) {    
     return  i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];}

/** * A cache of instances used by {@link Integer#valueOf(int)} and auto-boxing */
private static final Integer[] SMALL_VALUES = new Integer[256];
static {    
         for (int i = -128; i < 128; i++){        
                SMALL_VALUES[i + 128] = new Integer(i);    
         }
}
//当值在[-128,127)之间时,装箱操直接取已经cache好的Integer实例,所以i1==i2,当大于127时,每次都是new出来的Integer,指向不同的对象,所以i3!=i4
public class Main {
    public static void main(String[] args) {
 
        Integer a = 1;
        Integer b = 2;
        Integer c = 3;
        Integer d = 3;
        Integer e = 321;
        Integer f = 321;
        Long g = 3L;
        Long h = 2L;
         
        System.out.println(c==d);  //true
        System.out.println(e==f);   // false
        System.out.println(c==(a+b)); // true
        System.out.println(c.equals(a+b));//true
        System.out.println(g==(a+b));//false
        System.out.println(g.equals(a+b));//false
        System.out.println(g.equals(a+h));//true
    }
}


// Example 1: == comparison pure primitive – no autoboxing
        int i1 = 1;
        int i2 = 1;
        System.out.println("i1==i2 : " + (i1 == i2)); // true

        // Example 2: equality operator mixing object and primitive
        Integer num1 = 1; // autoboxing
        int num2 = 1;
        System.out.println("num1 == num2 : " + (num1 == num2)); // true

        // Example 3: special case - arises due to autoboxing in Java
        Integer obj1 = 1; // autoboxing will call Integer.valueOf()
        Integer obj2 = 1; // same call to Integer.valueOf() will return same
        // cached Object

        System.out.println("obj1 == obj2 : " + (obj1 == obj2)); // true

        int obj3 = 3;
        Integer obj4 = 3;
        Integer obj5 = new Integer(3);

        System.out.println("obj4 == obj5 :  " + (obj4 == obj5));//false
        System.out.println("obj3 == obj5 :  " + (obj3 == obj5));//true

        // Example 4: equality operator - pure object comparison
        Integer one = new Integer(1); // no autoboxing
        Integer anotherOne = new Integer(1);

        System.out.println("one == anotherOne : " + (one == anotherOne)); // false

//当 "=="运算符的两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。另外,对于包装器类型,equals方法并不会进行类型转换
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容