`
ruoyi
  • 浏览: 6311 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

Java中的装箱与拆箱(转)

    博客分类:
  • Java
阅读更多

J2SE5.0 后推出了自动装箱和拆箱的功能,以提高我们的开发效率,然而自动装箱和拆箱实际上是通过编译器来支持的(并非语言本身,或者说虚拟机),因而这种支持也隐藏了部分内部实质,再加上某些类的优化(比如 Integer 里面的缓存等,参看关于缓存 节),就更加容易在特定的环境下产生问题,并且如果不知道原来还无法调试。以下先是简单的介绍了编译器对装箱和拆箱的实现,并根据实现简单介绍一下可能会遇到的几个问题。

装箱和拆箱实现

以下装箱和拆箱代码:

       Object value  =   10 ;
       
int  intValue  =  (Integer)value;
       Integer newIntValue 
=   new  Integer( 10 );

 

编译成字节码如下:

     0 bipush 10

     2 invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [20]

     5 astore_1 [value]

     6 aload_1 [value]

     7 checkcast java.lang.Integer [21]

    10 invokevirtual java.lang.Integer.intValue() : int [26]

    13 istore_2 [intValue]

    14 new java.lang.Integer [21]

    17 dup

    18 bipush 10

    20 invokespecial java.lang.Integer(int) [30]

    23 astore_3 [newIntValue]

从以上字节码可以看到 10 首先调用 valueOf 方法转换为 Integer 实例,再赋值该 value ,而 value 强制转换成 Integer 类后,会调用 intValue 方法,后赋值给 intValue 。这就是用编译器来实现装箱和拆箱。

 

奇怪的 NullPointerException

查看以下代码:

       Integer value  =   null ;
       
int  intValue  =  value;

 

可以编译通过,但是运行的时候却会发生 NullPointerException 。这是由什么引起的呢?依然看一下字节码就可以了:

     0 aconst_null

     1 astore_1 [value]

     2 aload_1 [value]

    3 invokevirtual java.lang.Integer.intValue() : int [20]

     6 istore_2 [intValue]

从字节码中可以看到,从 value 赋值该 intValue 事实上是直接在 value 实例上调用 intValue 函数。

对当前代码,我们可以一眼就看出当前 value null 的问题,但是如果这个 null 是在很远以外的地方赋值的呢?或者是间接赋值呢?这个时候遇到这种问题就会比较诡异了。

 

相等与不相等问题

查看一下代码:

       Integer value1  =   100 ;
       Integer value2 
=   100 ;
       System.out.println(
" value1 == value2 is  "   +  (value1  ==  value2));
      
       Integer value3 
=   200 ;
       Integer value4 
=   200 ;
       System.out.println(
" value3 == value4 is  "   +  (value3  ==  value4));

 

这段代码会是什么结果?

value1 == value2 is true

value3 == value4 is false

 

两段代码就是值不一样,其他的都一样,竟然会有区别?这个奥妙就因为装箱过程中调用的是 valueOf 方法,而 valueOf 方法对值在 -128 127 之间的数值缓存了(参见关于缓存一节),因而 value1 value2 的引用是相同的,而 value3 value4 的引用是不一样的,而 == 比较的是引用,因而才会出现以上的结果。

这确的做法应该是:

       Integer value1  =   100 ;
       Integer value2 
=   100 ;
       System.out.println(
" value1 == value2 is  "   +  (value1.equals(value2)));
      
       Integer value3 
=   200 ;
       Integer value4 
=   200 ;

       System.out.println( " value3 == value4 is  "   +  (value3.equals(value4)));  

这样的结果就是预料的结果了:

value1 == value2 is true

value3 == value4 is true

 

所以我们要慎用“ == ”操作符。

 

String中的相等与不等

String 中也有类似的情况,查看一下代码:

       String str1  =   " abc " ;
       String str2 
=   " abc " ;
       System.out.println(
" str1 == str2 is  "   +  (str1  ==  str2));
      
       String str3 
=   new  String( " abc " );
       String str4 
=   new  String( " abc " );
       System.out.println(
" str3 == str4 is  "   +  (str3  ==  str4));

 

执行结果:

str1 == str2 is true

str3 == str4 is false

 

这是因为 str1 str2 使用的是同一个字符串,即在字符常量中的字符串,而 str3 str4 在使用字符常量中的字符为参数又创建出了两个新的字符串对象,因而在引用比较情况下是不等的。我们可以从字节码中得到这些信息(删除打印的代码):

     0 ldc <String "abc"> [20]

     2 astore_1 [str1 ]

     3 ldc <String "abc"> [20]

     5 astore_2 [str2]

     6 new java.lang.String [22]

     9 dup

    10 ldc <String "abc"> [20]

    12 invokespecial java.lang.String(java.lang.String) [24]

    15 astore_3 [str3 ]

    16 new java.lang.String [22]

    19 dup

    20 ldc <String "abc"> [20]

    22 invokespecial java.lang.String(java.lang.String) [24]

    25 astore 4 [str4]

正确的做法还是调用 equals 方法,而不是使用“ == ”操作符。

 

关于缓存

据目前信息,有缓存的类有: Byte Short Integer Long 以及 Boolean 类。而这种缓存也只是在调用 valueOf (静态)方法的时候才会存在(装箱正是调用了 valueOf 方法)。对整型,缓存的值都是 -128 127 (包括 -128 127 )之间,其他值都不缓存,而对 Boolean 类型只有 true false 值。代码如下:

public   final   class  Integer  extends  Number {
    
public   static  Integer valueOf( int  i) {
        
if (i  >=   - 128   &&  i  <=  IntegerCache.high)
            
return  IntegerCache.cache[i  +   128 ];
        
else
        
return   new  Integer(i);
}
public   final   class  Boolean {
    
public   static  Boolean valueOf( boolean  b) {
        
return  (b  ?  TRUE : FALSE);
    }


分享到:
评论

相关推荐

    Java自动装箱与拆箱深度解析:原理、应用与性能考量

    自动装箱和拆箱是Java语言中的重要特性,它们简化了基本数据类型与包装类之间的转换过程。然而,这两个机制也带来了一定的性能影响。为了编写更高效、更可维护的Java代码,开发者需要了解自动装箱和拆箱的工作原理、...

    Java中的自动装箱与拆箱Java开发Java经验技巧共6

    在Java编程语言中,自动装箱(Autoboxing)和自动拆箱(Unboxing)是两个重要的特性,它们简化了基本类型(如int、double等)与对应的包装类(如Integer、Double等)之间的转换过程。这些特性是在Java 5引入的,极大...

    JAVA装箱拆箱(很详细、易于理解)

    Java中的装箱和拆箱是面向对象编程中的一个重要概念,主要涉及到Java的自动类型转换机制。装箱是指将基本数据类型(如int、char、boolean等)转换为对应的包装器类对象,而拆箱则是相反的过程,即把包装器类的对象...

    Java中的自动装箱与拆箱_.docx

    在Java编程语言中,自动装箱(Autoboxing)和自动拆箱(Unboxing)是从Java 1.5版本开始引入的一项特性,其目的是简化原始类型(Primitive Types)与它们对应的包装类(Wrapper Classes)之间的转换过程。...

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

    本文将深入讲解Java装箱与拆箱的基本概念,并通过实例代码进行演示。 装箱(Boxing)是Java自动将基本数据类型转换为对应的包装类的过程。例如,int类型转换为Integer,char类型转换为Character等。这是Java 5引入...

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

    自动装箱与拆箱的实现原理 自动装箱是指Java将原始类型值转换成对应的对象的过程,如将int类型的变量转换成Integer对象。反之,将对象转换成原始类型值的过程称为拆箱。因为这里的装箱和拆箱是自动进行的非人为转换...

    Java中的自动装箱与拆箱:深入理解基本数据类型与对象的转换

    ### Java中的自动装箱与拆箱详解 #### 引言 在Java开发过程中,开发者经常需要处理各种数据类型之间的转换。对于基本数据类型与包装类之间的转换,Java提供了一个非常便利的功能——自动装箱和自动拆箱。这些功能...

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

    Java中自动装箱、拆箱引起的耗时详解 Java中自动装箱和拆箱是Java语言中一个重要的特性,它可以将基本数据类型和它们的包装类之间进行转换,这个过程是透明的,程序员不需要手动进行转换。但是,这个过程会引起一些...

    Java中的自动装箱和拆箱是什么?它们有什么作用?(java面试题附答案).txt

    ### Java中的自动装箱与拆箱 #### 一、概念介绍 在Java中,自动装箱(Autoboxing)和拆箱(Unboxing)是Java编译器提供的一种特性,用于在基本数据类型和对应的包装类之间进行自动转换。这种特性简化了编程过程中...

    Java中的自动装箱与拆箱

    自动装箱和拆箱从Java 1.5开始引入,目的是将原始类型值转自动地转换成对应的对象。自动装箱与拆箱的机制可以让我们在Java的变量赋值或者是方法调用等情况下使用原始类型或者对象类型更加简单直接。  如果你在Java...

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

    “深入理解Java中的装箱和拆箱” 一、什么是装箱?什么是拆箱? 在Java中,每种基本数据类型都有对应的包装器类型,例如int对应Integer、byte对应Byte等。装箱是指将基本数据类型自动转换为包装器类型的过程,而...

    java装箱拆箱.ppt

    java装箱拆箱.ppt java装箱拆箱.ppt

    深入剖析Java中的装箱和拆箱

    本文先讲述装箱和拆箱基本的东西,再来看一下面试笔试中经常遇到的与装箱、拆箱相关的问题。  以下是本文的目录大纲:  一.什么是装箱?什么是拆箱?  二.装箱和拆箱是如何实现的  三.面试中相关的问题  ...

    Java软件开发实战 Java基础与案例开发详解 8-3 装箱和拆箱 共4页.pdf

    拆箱与装箱相反,指的是将包装类对象转换回基本数据类型的过程。同样地,在Java SE 5.0及以后版本中,也支持自动拆箱的功能。 **示例代码**: ```java Integer i = 10; int j = i; // 自动拆箱 ``` 这段代码中,...

    java自动装箱拆箱深入剖析

    Java中的自动装箱和拆箱是自J2SE 5.0版本引入的特性,它极大地简化了基本数据类型与其对应的包装类之间的转换过程。基本数据类型包括int、double、boolean等,而包装类如Integer、Double和Boolean分别对应这些基本...

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

    Java中的自动装箱和拆箱是自JDK 1.5版本引入的一种语言特性,它极大地简化了基础数据类型(如int)与它们对应的包装类(如Integer)之间的转换过程。这一特性使得开发者无需手动创建包装类实例或使用显式类型转换,...

    Tedu正则表达式与Object与自动装箱与拆箱

    在 Java 5 中引入了自动装箱与拆箱的功能,使得开发者在使用基本类型和它们对应的包装类之间更加灵活。 **示例**: ```java // 自动装箱 int num = 10; Integer numObj = num; // numObj 是 Integer 对象 // 自动...

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

    Java中的装箱和拆箱是面向对象编程中的一个重要概念,主要涉及到基本数据类型与它们对应的包装器类之间的转换。在Java SE 5及以后的版本中,为了方便开发者使用,引入了自动装箱和拆箱的功能。 一、什么是装箱和...

    Java面试题06.装箱和拆箱.mp4

    Java面试题06.装箱和拆箱.mp4

    Java语言 包装类讲解案例代码 ( 设计目的(作用)和用途、自动装箱与拆箱、常用方法、 null和默认值)

    自动装箱与拆箱:自动装箱(Autoboxing)指的是自动地将基本数据类型转换为对应的包装类对象;自动拆箱(Unboxing)则是将包装类对象自动转换为基本数据类型。 常用方法:演示如何使用包装类中的这些常见方法。 null...

Global site tag (gtag.js) - Google Analytics