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

我在对另一个问题的回答中看到了这一点,提到Java规范的缺点:

缺点更多,这是一个微妙的话题。检查
  public class methodOverloading {
     public static void hello(Integer x){
          的System.out.println( “整数”);
     }

     public static void hello(long x){
          的System.out.println( “长”);
     }

     public static void main(String [] args){
         int i = 5;
         你好(ⅰ);
     }
}
</代码> 
     

这里打印的是“long”(没有自己检查过),因为编译器选择了自动装箱。使用自动装箱时请小心,否则根本不要使用它!

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

在我最初的扫描中,我同意这样一种说法,即基于将 i 声明为原语而不是对象,输出将是“long”。但是,如果你改变了

hello(long x)

hello(Long x)

输出将打印“整数”

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

0
当然它在扩大。 Int被扩大到很长时间。
额外 作者 EJP,

3 答案

是的,在测试中试用。你会看到“长”印。它正在扩大,因为在选择将它自动复制到Integer之前,Java会选择将int扩展为很长的一段,所以选择调用hello(long)方法。

编辑:原始帖子被引用

进一步编辑:第二个选项打印Integer的原因是因为没有“扩大”为一个较大的基元作为选项,所以它必须将它打包,因此Integer是唯一的选择。此外,java只会自动复制到原始类型,所以如果您离开hello(Long)并删除hello(Integer),它会给编译器一个错误。

0
额外

在第一种情况下,您的转换发生了扩大。在编译的类上运行“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

}

显然,您会看到I2L,它是扩展的整型至长字节码指令的助记符。请参阅参考此处

在另一种情况下,用对象“Long x”签名替换“long x”,您将在主要方法中使用此代码:

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

}

所以你看到编译器已经创建了指令Integer.valueOf(int),来封装包装器中的原语。

0
额外
我认为很明显Java必须在自动装箱之前加宽,因为旧代码依赖于加宽,如果代码突然变为自动装箱,则会中断。
额外 作者 Mr. Shiny and New 安宇,

这个例子的另一个有趣的地方是方法重载。类型加宽和方法重载的组合只能工作,因为编译器必须决定选择哪种方法。考虑下面的例子:

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

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

public static void main(String[] args){
   Collection col = new ArrayList();
   hello(col);
}

它不使用List的运行时类型,它使用的是Collection的编译时类型,从而打印“Collection”。

我鼓励您阅读 Effective Java ,这让我的眼睛看到了某些角落案例JLS。

0
额外