Java 这真的是对自动装箱的扩展吗?

Java 这真的是对自动装箱的扩展吗?,java,primitive,autoboxing,Java,Primitive,Autoboxing,我在参考Java规范的缺点时看到了这一点: 缺点更多,这是一个微妙的话题。退房: 这里将打印“long”(我自己没有检查),因为编译器选择加宽而不是自动装箱。使用自动装箱时要小心,否则根本不用 我们确定这实际上是一个加宽而不是自动装箱的例子,还是完全是另一回事 在我最初的扫描中,我同意这样的说法,即输出将是“长”的,因为I被声明为原语而不是对象。然而,如果你改变了 hello(long x) 到 输出将打印“整数” 这到底是怎么回事?我对java编译器/字节码解释器一无所知…是的,请在测试中试

我在参考Java规范的缺点时看到了这一点:

缺点更多,这是一个微妙的话题。退房:

这里将打印“long”(我自己没有检查),因为编译器选择加宽而不是自动装箱。使用自动装箱时要小心,否则根本不用

我们确定这实际上是一个加宽而不是自动装箱的例子,还是完全是另一回事

在我最初的扫描中,我同意这样的说法,即输出将是“长”的,因为
I
被声明为原语而不是对象。然而,如果你改变了

hello(long x)

输出将打印“整数”


这到底是怎么回事?我对java编译器/字节码解释器一无所知…

是的,请在测试中试用。您将看到“long”打印。它是加宽的,因为Java在选择将int自动装箱为整数之前,会选择将int加宽为long,所以选择调用hello(long)方法

编辑:


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

在第一种情况下,发生了一个加宽的转换。在编译类上运行“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,它是将整数扩展为长字节码指令的助记符。见参考资料

在另一种情况下,将“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

}

因此,您可以看到编译器创建了Integer.valueOf(int)指令,用于在包装器中装箱原语。

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

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”


我鼓励您阅读,这让我看到了JLS的一些角落案例。

我认为很明显,Java在自动装箱之前必须加宽,因为旧代码依赖于加宽,如果代码突然变为自动装箱,就会中断。当然,它在加宽。Int被加宽为long。
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

}
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);
}