【问题标题】:How does auto boxing/unboxing work in Java?自动装箱/拆箱如何在 Java 中工作?
【发布时间】:2014-03-25 23:41:16
【问题描述】:

自 JDK 5.0 起,Java 中引入了自动装箱/拆箱。这个技巧很简单也很有帮助,但是当我开始测试包装类和原始类型之间的不同转换时,我真的很困惑自动装箱的概念在 Java 中是如何工作的。例如:

拳击

int intValue = 0;
Integer intObject = intValue;
byte byteValue = 0;
intObject = byteValue; // ==> Error

在尝试了不同的情况(shortlongfloatdouble)之后,编译器唯一接受的情况是当做作运算符右边的值的类型是@987654327 @。 当我查看Integer.class 的源代码时,我发现它只实现了一个带有int 参数的构造函数。

所以我的结论是自动装箱的概念是基于在包装类中实现的构造函数。我想知道这个结论是真的还是自动装箱使用了另一个概念?

拆箱

Integer intObject = new Integer(0);
byte byteValue = intObject; // ==> Error (the same Error with short)
int intValue = intObject; 
double doubleValue = intObject;

我关于拆箱的结论是包装类给出了对应类型的对象包装的值(Integer==>int),然后编译器使用转换原始类型的常用规则(byte => short => int => long => float => double)。 我想知道这个结论是真的还是自动开箱使用了另一个概念?

【问题讨论】:

  • 您是否阅读了有关自动装箱的 Java 语言规范部分? docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.7
  • byte byteValue = intObject; - 无论intObject 是对象还是原始类型,您都会意识到这是一个错误,对吧?
  • 我认为编译器使用方法Integer.intValue() 来拆箱包装的值,对吗?
  • @LouisWasserman 非常感谢您的链接真的很有帮助,它回答了我的问题。

标签: java autoboxing unboxing


【解决方案1】:

如有疑问,请检查字节码:

Integer n = 42;

变成:

0: bipush        42
2: invokestatic  #16                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1      

所以实际上,valueOf() 用于与构造函数相反(其他包装类也是如此)。这是有益的,因为它允许缓存,并且不会强制在每个装箱操作上创建新对象。

反面如下:

int n = Integer.valueOf(42);

变成:

0: bipush        42
2: invokestatic  #16                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: invokevirtual #22                 // Method java/lang/Integer.intValue:()I
8: istore_1      

即使用intValue()(同样,它与其他包装器类型类似)。这实际上是所有自动(取消)装箱归结为。

您可以分别在JLS §5.1.7JLS §5.1.8 中阅读有关装箱和拆箱转换的信息。

【讨论】:

  • 事实上我是java初学者(我不懂字节码),所以当我开始阅读自动装箱的一章时,它只给出了一些自动装箱/拆箱限制的例子,而不是所有规则,然后我尝试解析所有案例,并想确认我对这个概念的理解是否得到纠正。
  • @NarutoBijuMode 我认为您的主要误解是关于如何(取消)装箱发生。正如我在答案中指出的那样,它只是归结为两种特定方法的调用; valueOf()intValue()(分别)。
  • 感谢您的帮助 :),我想我是愚蠢的人,他提出了一个我现在无法理解的解释(我应该了解更多关于 java 的知识)。谢谢。
  • 我认为隐式装箱/拆箱很昂贵,而且从未真正推荐过。我想约书亚·布洛赫可能会这么说?那么现在是否可以接受使用隐式转换而不必显式调用valueOf()intValue()
【解决方案2】:

可以通过使用 javac -XD-printflat 的开关来消除这种混乱,这在这种情况下非常有用。因此,要解开装箱和拆箱的奥秘,您可以编写一个简单的程序,如下所示:

import java.util.*;

public class Boxing{
  public static void main(String[] args){
    Double d1 = 10.123;
    Float  f1 = 12.12f;
    Long   l1 = 1234L;
    Integer i1 = 55555;
    Short   s1 = 2345;
    Byte    b1 = 89;

    double d2 = d1;
    float  f2 = f1;
    long   l2 = l1;
    int    i2 = i1;
    short  s2 = s1;
    byte   b2 = b1;
  }
} 

现在我们将上面的文件编译为:

javac -XD-printflat -d src/ Boxing.java

此命令的输出是一个 java 文件,其中删除了所有语法糖(通用类型、增强的 for 循环以及在本例中的装箱-拆箱等)。以下是输出

import java.util.*;

public class Boxing {

    public Boxing() {
        super();
    }

    public static void main(String[] args) {
        Double d1 = Double.valueOf(10.123);
        Float f1 = Float.valueOf(12.12F);
        Long l1 = Long.valueOf(1234L);
        Integer i1 = Integer.valueOf(55555);
        Short s1 = Short.valueOf(2345);
        Byte b1 = Byte.valueOf(89);
        double d2 = d1.doubleValue();
        float f2 = f1.floatValue();
        long l2 = l1.longValue();
        int i2 = i1.intValue();
        short s2 = s1.shortValue();
        byte b2 = b1.byteValue();
    }
}

这就是java进行装箱拆箱的方式。使用 valueOf 和 ***Value 方法。

【讨论】:

    【解决方案3】:

    自动装箱和自动拆箱

    自动装箱意味着当我们尝试将原始数据分配给对象类型时,它会自动将自身转换为对象类型。该过程称为自动装箱。当对象类型转换为原始类型时,称为拆箱...试着从下面的例子中理解它。

    class Demo{
    public static void main(String args[]){
        int x=100;
    
        //Integer iob=x; //Illegal jdk1.4
        Integer iob=Integer.valueOf(x); //Legal at JDK1.4 =>Boxing
    
        Integer iob2=x; //Legal JDK1.5 - Autoboxing
        System.out.println(iob2);
    }
    

    }

    自动装箱的另一个例子

    class Demo{
    public static void main(String args[]){
        Integer iob=new Integer(100);    
        int x;
        x=iob; //Legal => auto unboxing
        System.out.println(x);
    }
    

    }

    自动拆箱示例

    class Demo{
    public static void main(String args[]){
        Integer iob=new Integer(100);
        int x=iob; //Auto unboxing ==>Assignment
    
    }
    

    }

    谢谢你..

    【讨论】:

      【解决方案4】:

      将以下代码视为自动拆箱的示例:

      System.out.println('b'+ new Integer(63));
      

      以下是上述代码的编译方式:

      第 1 步:实例化 Object Integer 63,然后自动取消装箱到 int 63

      new Integer(63)
      

      第 2 步:将 char 'b' 转换为数值,即 98

      第三步:两个值相加:98+63

      第 4 步:输出为 161

      【讨论】:

        猜你喜欢
        • 2011-05-02
        • 1970-01-01
        • 2018-06-20
        • 2016-06-27
        • 2011-01-19
        • 2015-02-23
        • 1970-01-01
        相关资源
        最近更新 更多