Java 推广 Primitives 和 Wrappers + 盒装!什么进程在这里做 JVM

Java Primitives and Wrappers promoted + boxed! What process is doing JVM here

我正在尝试购买 1Z0-815。我制作的这段代码:

public class PromotedPlusBoxed {
    public static void main(String[] args) {
       /*AUTOMATIC PROMOTION*/   
       final byte byteValue = 10;
       final short shortValue = 10;        
       final char charValue = 10;
       final int intValue = 10;
       final long longValue = 10;
       final float floatValue = 10;
       final double doubleValue = 10;
       /**/
       final Byte byteWrapperValue = 10;/*WHAT PROCESS IS HERE? A HIDDEN = (byte)10;? a performing a single boxed process.*/
       final Short shortWrapperValue = 10;/*WHAT PROCESS IS HERE? A HIDDEN = (short)10;? a performing a single boxed process.*/        
       final Character charWrapperValue = 10;/*WHAT PROCESS IS HERE? A HIDDEN = (char)10;? a performing a single boxed process.*/        
       final Integer intWrapperValue = 10;
       final Long longWrapperValue = 10;/*CAN'T PERFORM TWO-PHASE PROCESS 1). PROMOTED + 2).BOXED*/
       final Float floatWrapperValue = 10;/*CAN'T PERFORM TWO-PHASE PROCESS 1). PROMOTED + 2).BOXED*/
       final Double doubleWrapperValue = 10;/*CAN'T PERFORM TWO-PHASE PROCESS 1). PROMOTED + 2).BOXED*/
    }    
}

我也理解基元部分,我知道我不能这样做。

  final Long longWrapperValue = 10;/*CAN'T PERFORM TWO-PHASE PROCESS 1). PROMOTED + 2).BOXED*/
  final Float floatWrapperValue = 10;/*CAN'T PERFORM TWO-PHASE PROCESS 1). PROMOTED + 2).BOXED*/
  final Double doubleWrapperValue = 10;/*CAN'T PERFORM TWO-PHASE PROCESS 1). PROMOTED + 2).BOXED*/

因为 10 是一个文字 int,所以需要首先将 2 进程提升为 float、long 和 double,然后装箱到各自的包装器。

但这是编译。

 final Byte byteWrapperValue = 10;/*WHAT PROCESS IS HERE? A HIDDEN = (byte)10;? a performing a single boxed process.*/
 final Short shortWrapperValue = 10;/*WHAT PROCESS IS HERE? A HIDDEN = (short)10;? a performing a single boxed process.*/        
 final Character charWrapperValue = 10;/*WHAT PROCESS IS HERE? A HIDDEN = (char)10;? a performing a single boxed process.*/    

这里的流程是什么? 10 被提升为字节,然后装箱为字节,这是一个 2 进程吗?但不适用于 Long 在此过程中,Long 和 Byte、Character、Short 之间的区别是什么。

总而言之:我想了解为什么文字 int 可以装箱成 Byte,Character,Short 而不是 Long。

答案就在字节码中。如果我们想查看它,我们必须先编译它,所以将您的最后一个示例更改为:

final Byte byteWrapperValue = 10;
final Short shortWrapperValue = 10;
final Character charWrapperValue = 10;
final Integer intWrapperValue = 10;
final Long longWrapperValue = 10L;       <-- Added L
final Float floatWrapperValue = 10.0f;   <-- Added .0f
final Double doubleWrapperValue = 10.0d; <-- Added .0d

for the sake of readability I removed the LINENUMBER and ASTORE instructions)

然后在查看字节码时我们会看到:

   L0
    BIPUSH 10
    INVOKESTATIC java/lang/Byte.valueOf (B)Ljava/lang/Byte;
   L1
    BIPUSH 10
    INVOKESTATIC java/lang/Short.valueOf (S)Ljava/lang/Short;
   L2
    BIPUSH 10
    INVOKESTATIC java/lang/Character.valueOf (C)Ljava/lang/Character;
   L3
    BIPUSH 10
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
   L4
    LDC 10
    INVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long;
   L5
    LDC 10.0
    INVOKESTATIC java/lang/Float.valueOf (F)Ljava/lang/Float;
   L6
    LDC 10.0
    INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double;

请注意,对于 Integer 之前的每个 10,我们都使用 BIPUSH 指令(您可以在 wikipedia 处看到所有指令),这意味着它会推送一个 字节作为一个整数到堆栈上。

而对于 10L10.0f10.0d 我们使用 LDC 指令,它类似但不完全相同,它用于加载 constant来自常量池,可以是静态的也可以是动态的。

(后面可能是当初编译不通过的原因)

您还看到编译器使用相应的 Wrapper-class 方法自动装箱压入堆栈的值。 (例如 Byte.valueOf()

同样在分析一个简单的例子时:

long l = 10;
Long l2 = l;

大家可以看到一样的,这次只是分两步搞定:

   L0
    LDC 10 # load the value from the constant pool
   L1
    INVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long; # convert the value to the wrapper type with autoboxing

更多阅读:

  • How java auto boxing/unboxing works?
  • Why do we use autoboxing and unboxing in Java?
  • How does bipush work in JVM?