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

emagni 发布于 2018-03-04 autoboxing 最后更新 2018-03-04 01:04 1118 浏览

我在an answer to another question中看到了这个,参考java规范的缺点:

There are more shortcomings and this is a subtle topic. Check this out:
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);
     }
}
Here "long" would be printed (haven't checked it myself), because the compiler choses >widening over autoboxing. Be careful when using autoboxing or don't use it at all!
我们确定这实际上是展开而不是自动装箱的示例,还是完全是其他功能? 在我最初的扫描中,我同意以i被声明为基元而不是对象为基础的输出“长”的说法。但是,如果你改变了
hello(long x)
hello(Long x)
输出将打印“整数” 这里究竟发生了什么?我对java的编译器/字节码解释器一无所知。
已邀请:

ddolor

赞同来自:

是的,在测试中试用。你会看到“长”印。它正在扩大,因为在选择将它自动复制到Integer之前,Java会选择将int扩展为很长的一段,所以选择调用hello(long)方法。 编辑:the original post being referenced。 进一步编辑:第二个选项打印Integer的原因是因为没有“扩大”为一个较大的基元作为选项,所以它必须将它打包,因此Integer是唯一的选择。此外,java只会自动复制到原始类型,所以如果您离开hello(Long)并删除hello(Integer),它会给编译器一个错误。

ased

赞同来自:

在第一种情况下,您的转换发生了扩大。在编译的类上运行“javap”实用程序(包含在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,它是扩展的整型至长字节码指令的助记符。请参阅参考here。 在另一种情况下,用对象“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),来封装包装器中的原语。

ysit

赞同来自:

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

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的某些角落案例开放了​​眼界。