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

Java 装箱与拆箱详解

前言:

要理解装箱和拆箱的概念,就要理解Java数据类型

装箱:把基本类型用它们相应的引用类型包装起来,使其具有对象的性质。int包装成Integer、float包装成Float

拆箱:和装箱相反,将引用类型的对象简化成值类型的数据

Integer a = 100;         这是自动装箱 (编译器调用的是static Integer valueOf(int i))
int   b = new Integer(100); 这是自动拆箱

看下面一段代码

m1

public class DataType {

  public static void main(String args[]) {
    DataType dt = new DataType();
    dt.m11();
    dt.m12();

  }

  public void m11() {
    Integer a = new Integer(100);
    Integer b = 100;
    System.out.println("m11 result " + (a == b));
  }

  public void m12() {
    Integer a = new Integer(128);
    Integer b = 128;
    System.out.println("m12 result " + (a == b));
  }

}

  打印结果是什么?

m11 result false
m12 result false

“==”比较的是地址,而a和b两个对象的地址不同,即是两个对象,所以都是false

通过javap解析字节码,内容如下

public void m11();
 Code:
  0:  new   #44; //class java/lang/Integer
  3:  dup
  4:  bipush 100
  6:  invokespecial  #46; //Method java/lang/Integer."<init>":(I)V
  9:  astore_1
  10: bipush 100
  12: invokestatic  #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
  15: astore_2
  16: getstatic    #53; //Field java/lang/System.out:Ljava/io/PrintStream;
  19: new   #59; //class java/lang/StringBuilder
  22: dup
  23: ldc   #61; //String m11 result
  25: invokespecial  #63; //Method java/lang/StringBuilder."<init>":(Ljava/la
ng/String;)V
  28: aload_1
  29: aload_2
  30: if_acmpne    37
  33: iconst_1
  34: goto  38
  37: iconst_0
  38: invokevirtual  #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
  41: invokevirtual  #70; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
  44: invokevirtual  #74; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
  47: return

public void m12();
 Code:
  0:  new   #44; //class java/lang/Integer
  3:  dup
  4:  sipush 128
  7:  invokespecial  #46; //Method java/lang/Integer."<init>":(I)V
  10: astore_1
  11: sipush 128
  14: invokestatic  #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
  17: astore_2
  18: getstatic    #53; //Field java/lang/System.out:Ljava/io/PrintStream;
  21: new   #59; //class java/lang/StringBuilder
  24: dup
  25: ldc   #82; //String m12 result
  27: invokespecial  #63; //Method java/lang/StringBuilder."<init>":(Ljava/la
ng/String;)V
  30: aload_1
  31: aload_2
  32: if_acmpne    39
  35: iconst_1
  36: goto  40
  39: iconst_0
  40: invokevirtual  #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
  43: invokevirtual  #70; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
  46: invokevirtual  #74; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
  49: return
</init></init></init></init>
 

m2

public class DataType {

  public static void main(String args[]) {
    DataType dt = new DataType();
    dt.m21();
    dt.m22();
  }

  public void m21() {
    Integer a = new Integer(100);
    Integer b = new Integer(100);
    System.out.println("m21 result " + (a == b));
  }

  public void m22() {
    Integer a = new Integer(128);
    Integer b = new Integer(128);
    System.out.println("m22 result " + (a == b));
  }

}

  打印结果是

m21 result false
m22 result false

a和b仍是两个对象

javap解析内容

public void m21();
 Code:
  0:  new   #44; //class java/lang/Integer
  3:  dup
  4:  bipush 100
  6:  invokespecial  #46; //Method java/lang/Integer."<init>":(I)V
  9:  astore_1
  10: new   #44; //class java/lang/Integer
  13: dup
  14: bipush 100
  16: invokespecial  #46; //Method java/lang/Integer."<init>":(I)V
  19: astore_2
  20: getstatic    #53; //Field java/lang/System.out:Ljava/io/PrintStream;
  23: new   #59; //class java/lang/StringBuilder
  26: dup
  27: ldc   #84; //String m21 result
  29: invokespecial  #63; //Method java/lang/StringBuilder."<init>":(Ljava/la
ng/String;)V
  32: aload_1
  33: aload_2
  34: if_acmpne    41
  37: iconst_1
  38: goto  42
  41: iconst_0
  42: invokevirtual  #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
  45: invokevirtual  #70; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
  48: invokevirtual  #74; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
  51: return

public void m22();
 Code:
  0:  new   #44; //class java/lang/Integer
  3:  dup
  4:  sipush 128
  7:  invokespecial  #46; //Method java/lang/Integer."<init>":(I)V
  10: astore_1
  11: new   #44; //class java/lang/Integer
  14: dup
  15: sipush 128
  18: invokespecial  #46; //Method java/lang/Integer."<init>":(I)V
  21: astore_2
  22: getstatic    #53; //Field java/lang/System.out:Ljava/io/PrintStream;
  25: new   #59; //class java/lang/StringBuilder
  28: dup
  29: ldc   #86; //String m22 result
  31: invokespecial  #63; //Method java/lang/StringBuilder."<init>":(Ljava/la
ng/String;)V
  34: aload_1
  35: aload_2
  36: if_acmpne    43
  39: iconst_1
  40: goto  44
  43: iconst_0
  44: invokevirtual  #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
  47: invokevirtual  #70; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
  50: invokevirtual  #74; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
  53: return

m3

public class DataType {

  public static void main(String args[]) {
    DataType dt = new DataType();
    dt.m31();
    dt.m32();
  }

  public void m31() {
    Integer a = 100;
    Integer b = 100;
    System.out.println("m31 result " + (a == b));
  }

  public void m32() {
    Integer a = 128;
    Integer b = 128;
    System.out.println("m32 result " + (a == b));
  }

}

  打印结果

m31 result true
m32 result false

为什么有第一个是true,第二个是false呢?观察javap解析的数据

javap解析内容

public void m31();
 Code:
  0:  bipush 100
  2:  invokestatic  #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
  5:  astore_1
  6:  bipush 100
  8:  invokestatic  #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
  11: astore_2
  12: getstatic    #53; //Field java/lang/System.out:Ljava/io/PrintStream;
  15: new   #59; //class java/lang/StringBuilder
  18: dup
  19: ldc   #88; //String m31 result
  21: invokespecial  #63; //Method java/lang/StringBuilder."<init>":(Ljava/la
ng/String;)V
  24: aload_1
  25: aload_2
  26: if_acmpne    33
  29: iconst_1
  30: goto  34
  33: iconst_0
  34: invokevirtual  #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
  37: invokevirtual  #70; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
  40: invokevirtual  #74; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
  43: return

public void m32();
 Code:
  0:  sipush 128
  3:  invokestatic  #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
  6:  astore_1
  7:  sipush 128
  10: invokestatic  #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
  13: astore_2
  14: getstatic    #53; //Field java/lang/System.out:Ljava/io/PrintStream;
  17: new   #59; //class java/lang/StringBuilder
  20: dup
  21: ldc   #90; //String m32 result
  23: invokespecial  #63; //Method java/lang/StringBuilder."<init>":(Ljava/la
ng/String;)V
  26: aload_1
  27: aload_2
  28: if_acmpne    35
  31: iconst_1
  32: goto  36
  35: iconst_0
  36: invokevirtual  #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
  39: invokevirtual  #70; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
  42: invokevirtual  #74; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
  45: return

m4

public class DataType {

  public static void main(String args[]) {
    DataType dt = new DataType();
    dt.m41();
    dt.m42();
  }

  public void m41() {
    Integer a = Integer.valueOf(100);
    Integer b = 100;
    System.out.println("m41 result " + (a == b));
  }

  public void m42() {
    Integer a = Integer.valueOf(128);
    Integer b = 128;
    System.out.println("m42 result " + (a == b));
  }
}

  打印结果

m41 result true
m42 result false

javap解析内容

public void m41();
 Code:
  0:  bipush 100
  2:  invokestatic  #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
  5:  astore_1
  6:  bipush 100
  8:  invokestatic  #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
  11: astore_2
  12: getstatic    #53; //Field java/lang/System.out:Ljava/io/PrintStream;
  15: new   #59; //class java/lang/StringBuilder
  18: dup
  19: ldc   #92; //String m41 result
  21: invokespecial  #63; //Method java/lang/StringBuilder."<init>":(Ljava/la
ng/String;)V
  24: aload_1
  25: aload_2
  26: if_acmpne    33
  29: iconst_1
  30: goto  34
  33: iconst_0
  34: invokevirtual  #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
  37: invokevirtual  #70; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
  40: invokevirtual  #74; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
  43: return

public void m42();
 Code:
  0:  sipush 128
  3:  invokestatic  #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
  6:  astore_1
  7:  sipush 128
  10: invokestatic  #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
teger;
  13: astore_2
  14: getstatic    #53; //Field java/lang/System.out:Ljava/io/PrintStream;
  17: new   #59; //class java/lang/StringBuilder
  20: dup
  21: ldc   #94; //String m42 result
  23: invokespecial  #63; //Method java/lang/StringBuilder."<init>":(Ljava/la
ng/String;)V
  26: aload_1
  27: aload_2
  28: if_acmpne    35
  31: iconst_1
  32: goto  36
  35: iconst_0
  36: invokevirtual  #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la
ng/StringBuilder;
  39: invokevirtual  #70; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
  42: invokevirtual  #74; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
  45: return

}

分析

javap是Java自带的一个工具,可以反编译,也可以查看Java编译器生成的字节码(上面代码只使用了javap -c DataType),是分析代码的一个好工具,具体怎么使用请Google一下

先看一下m4,为什么运行结果中出现了“true”呢,true说明a、b是同一个对象。 

但a对象是调用Integer.valueOf()生成的,b是通过自动装箱生成的对象,为什么会是同一个对象呢?再看一下字节码吧,毕竟Java程序是依靠虚拟机运行字节码实现的。

m41这个方法只适用了一次valueOf(),但字节码中出现了两次,说明自动装箱时也调用了valueOf()。

下面是valueOf()具体实现

/**
 * Returns a <tt>Integer</tt> instance representing the specified
 * <tt>int</tt> value.
 * If a new <tt>Integer</tt> 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.
 *
 * @param i an <code>int</code> value.
 * @return a <tt>Integer</tt> instance representing <tt>i</tt>.
 * @since 1.5
 */
public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
  return IntegerCache.cache[i + offset];
}
  return new Integer(i);
}

在【-128,127】之间的数字,valueOf返回的是缓存中的对象,所以两次调用返回的是同一个对象。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • java自动装箱拆箱深入剖析

    这个是jdk1.5以后才引入的新的内容,作为秉承发表是最好的记忆,毅然决定还是用一篇博客来代替我的记忆: java语言规范中说道:在许多情况下包装与解包装是由编译器自行完成的(在这种情况下包装成为装箱,解包装称为拆箱): 其实按照我自己的理解自动装箱就可以简单的理解为将基本数据类型封装为对象类型,来符合java的面向对象:例如用int来举例: 复制代码 代码如下: //声明一个Integer对象 Integer num = 10; //以上的声明就是用到了自动的装箱:解析为 Integer nu

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

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

  • 浅谈Java自动装箱与拆箱及其陷阱

    在本文中,笔者向大家介绍下Java中一个非常重要也非常有趣的特性,就是自动装箱与拆箱,并从源码中解读自动装箱与拆箱的原理,同时这种特性也留有一个陷阱.开发者如果不注意,就会很容易跌入这个陷阱. 自动装箱(Autoboxing) 定义 大家在平时编写Java程序时,都常常以以下方式来定义一个Integer对象: Integer i=100; 从上面的代码中,大家可以得知,i为一个Integer类型的引用,100为Java中的基础数据类型(primitive data type).而这种直接将一个基

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

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

  • java编程中自动拆箱与自动装箱详解

    什么是自动装箱拆箱 基本数据类型的自动装箱(autoboxing).拆箱(unboxing)是自J2SE 5.0开始提供的功能. 一般我们要创建一个类的对象实例的时候,我们会这样: Class a = new Class(parameter); 当我们创建一个Integer对象时,却可以这样: Integer i = 100; (注意:不是 int i = 100; ) 实际上,执行上面那句代码的时候,系统为我们执行了:Integer i = Integer.valueOf(100); (感谢@

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

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

  • java 实现单链表逆转详解及实例代码

    java 实现单链表逆转详解 实例代码: class Node { Node next; String name; public Node(String name) { this.name = name; } /** * 打印结点 */ public void show() { Node temp = this; do { System.out.print(temp + "->"); temp = temp.next; }while(temp != null); System.o

  • Java 使用json-lib处理JSON详解及实例代码

    Java 使用json-lib处理JSON详解 [项目环境] <dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib</artifactId> <version>2.4</version> <classifier>jdk15</classifier> </dependency> 1. JSON 数组对象转化

  • Java中的Static class详解及实例代码

     Java中的Static class详解 Java中的类可以是static吗?答案是可以.在Java中我们可以有静态实例变量.静态方法.静态块.类也可以是静态的. java允许我们在一个类里面定义静态类.比如内部类(nested class).把nested class封闭起来的类叫外部类.在java中,我们不能用static修饰顶级类(top level class).只有内部类可以为static. 静态内部类和非静态内部类之间到底有什么不同呢?下面是两者间主要的不同. (1)内部静态类不需

  • java LRU(Least Recently Used )详解及实例代码

    java LRU(Least Recently Used )详解 LRU是Least Recently Used 的缩写,翻译过来就是"最近最少使用",LRU缓存就是使用这种原理实现,简单的说就是缓存一定量的数据,当超过设定的阈值时就把一些过期的数据删除掉,比如我们缓存10000条数据,当数据小于10000时可以随意添加,当超过10000时就需要把新的数据添加进来,同时要把过期数据删除,以确保我们最大缓存10000条,那怎么确定删除哪条过期数据呢,采用LRU算法实现的话就是将最老的数据

  • C++/java 继承类的多态详解及实例代码

    C++/java 继承类的多态详解 学过C++和Java的人都知道,他们二者由于都可以进行面向对象编程,而面向对象编程的三大特性就是封装.继承.多态,所有今天我们就来简单了解一下C++和Java在多态这方面的不同. 首先我们各看一个案例. C++ //测试继承与多态 class Animal { public: char name[128]; char behavior[128]; void outPut() { cout << "Animal" << endl

  • Java大文件上传详解及实例代码

    Java大文件上传详解 前言: 上周遇到这样一个问题,客户上传高清视频(1G以上)的时候上传失败. 一开始以为是session过期或者文件大小受系统限制,导致的错误.查看了系统的配置文件没有看到文件大小限制,web.xml中seesiontimeout是30,我把它改成了120.但还是不行,有时候10分钟就崩了. 同事说,可能是客户这里服务器网络波动导致网络连接断开,我觉得有点道理.但是我在本地测试的时候发觉上传也失败,网络原因排除. 看了日志,错误为: java.lang.OutOfMemor

  • Java中的代理模式详解及实例代码

    java 代理模式详解 前言: 在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为"代理"的第三者来实现间接引用.代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务. 简单来说代理模式就是通过一个代理对象去访问一个实际对象,并且可以像装饰模式一样给对象添加一些功能. 静态代理 所谓静态代理即在程序运行前代理类就已经存在,也就是说我们编写代码的时候就已经把代理类的代码写好了,而动态代理则

  • java 反射和动态代理详解及实例代码

    一.java中的反射 1.通过反射加载类的属性和方法实例代码: /** * java.lang.Class 是反射的源头 * 我们创建了一个类,通过编译(javac.exe)生成对应的class文件,之后我们通过java.exe加载(jvm的类加载器加载)此class文件 * 此class文件加载到内存后,就是一个运行时类,存在缓存区,这个运行时类本事就是一个Class的实例 * 每一个运行时类只加载一次, */ Class<StudentExam> clazz = StudentExam.c

  • JAVA多线程之方法 JOIN详解及实例代码

    JAVA多线程 JOIN 对于Java开发人员,多线程应该是必须熟练应用的知识点,特别是开发基于Java语言的产品.本文将深入浅出的表述Java多线程的知识点,在后续的系列里将侧重于Java5由Doug Lea教授提供的Concurrent并行包的设计思想以及具体实现与应用. 如何才能深入浅出呢,我的理解是带着问题,而不是泛泛的看.所以该系列基本以解决问题为主,当然我也非常希望读者能够提出更好的解决问题的方案以及提出更多的问题.由于水平有限,如果有什么错误之处,请大家提出,共同讨论,总之,我希望

随机推荐