这是否真的在扩大与自动装箱?

And*_*ndy 28 java primitive autoboxing

我在回答另一个问题时看到了这一点,参考了​​Java规范的缺点:

还有更多的缺点,这是一个微妙的话题.看看这个:

public class methodOverloading{
     public static void hello(Integer x){
          System.out.println("Integer");
     }

     public static void hello(long x){
          System.out.println("long");
     }

     public static void main(String[] args){
         int i = 5;
         hello(i);
     }
}
Run Code Online (Sandbox Code Playgroud)

这里将打印"long"(我自己没有检查过),因为编译器会选择加宽自动装箱.使用自动装箱时要小心,或者根本不使用它!

我们是否确定这实际上是扩大而不是自动装箱的一个例子,还是完全不同于其他东西?

在我的初始扫描中,我同意声明输出i在声明为基元而不是对象的基础上"长" .但是,如果你改变了

hello(long x)
Run Code Online (Sandbox Code Playgroud)

hello(Long x)
Run Code Online (Sandbox Code Playgroud)

输出将打印"整数"

这里到底发生了什么?我对java的编译器/字节码解释器一无所知...

Cam*_*pka 13

在第一种情况下,您正在进行扩大转换.在编译的类上运行"javap"实用程序(包含w/JDK)时可以看到:

public static void main(java.lang.String[]);
  Code:
   0:   iconst_ 5
   1:   istore_ 1
   2:   iload_ 1
   3:   i2l
   4:   invokestatic    #6; //Method hello:(J)V
   7:   return

}
Run Code Online (Sandbox Code Playgroud)

显然,你会看到I2L,它是扩展Integer-To-Long字节码指令的助记符.见这里的参考.

而在另一种情况下,用对象"Long x"签名替换"long x",您将在main方法中使用以下代码:

public static void main(java.lang.String[]);
  Code:
   0:   iconst_ 5
   1:   istore_ 1
   2:   iload_ 1
   3:   invokestatic    #6; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   6:   invokestatic    #7; //Method hello:(Ljava/lang/Integer;)V
   9:   return

}
Run Code Online (Sandbox Code Playgroud)

所以你看到编译器创建了指令Integer.valueOf(int),用于在包装器中包装原语.

  • 我认为很明显Java必须在自动装箱之前加宽,因为较旧的代码依赖于加宽,如果该代码突然改为自动装箱,则会破坏. (5认同)

Mik*_*one 5

是的,在测试中尝试一下。您将看到打印的“long”。它是加宽的,因为 Java 会选择将 int 加宽为 long,然后才选择将其自动装箱为 Integer,因此选择调用 hello(long) 方法。

编辑:被引用的原始帖子

进一步编辑:第二个选项打印 Integer 的原因是因为没有“扩展”到更大的原语作为选项,所以它必须将它装箱,因此 Integer 是唯一的选择。此外,java 只会自动装箱到原始类型,因此如果您保留 hello(Long) 并删除 hello(Integer),则会出现编译器错误。