【问题标题】:Is this really widening vs autoboxing?这真的是扩大与自动装箱吗?
【发布时间】:2010-09-05 12:25:10
【问题描述】:

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

还有更多的缺点,这是一个微妙的话题。签出this

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

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

我们确定这实际上是一个扩大而不是自动装箱的例子,还是完全是别的什么?

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

hello(long x)

hello(Long x)

输出将打印“整数”

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

【问题讨论】:

  • 当然它在扩大。 Int 加宽为 long。

标签: java primitive autoboxing


【解决方案1】:

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

编辑:the original post being referenced

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

【讨论】:

    【解决方案2】:

    在第一种情况下,您的转化率正在扩大。在编译的类上运行“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,它是扩展 Integer-To-Long 字节码指令的助记符。请参阅参考资料here

    在另一种情况下,将“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),将原语装箱到包装器中。

    【讨论】:

    • 我认为很明显,Java 必须在自动装箱之前加宽,因为旧代码依赖于加宽,如果该代码突然更改为自动装箱,就会中断。
    【解决方案3】:

    这个例子的另一个有趣的地方是方法重载。类型扩展和方法重载的组合仅起作用,因为编译器必须决定选择哪种方法。考虑以下示例:

    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 的一些角落案例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-19
      • 2013-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-11
      • 2010-10-20
      相关资源
      最近更新 更多