【问题标题】:Expand on this autoboxing explanation展开此自动装箱说明
【发布时间】:2012-03-15 04:37:29
【问题描述】:

我问:

自动装箱/拆箱是在运行时(JVM)还是在编译时(编译器)完成?

我收到了这个答案:

自动装箱是通过编译器在代码中插入方法调用和强制转换来实现的。这些调用和强制转换在运行时处理。

请详细说明。

【问题讨论】:

  • 你有什么不明白的?
  • 我会更详细地解释,但我不明白哪一部分你不清楚。你知道什么是自动装箱吗?

标签: java boxing autoboxing


【解决方案1】:

来自 Java 规范

Chapter 5. Conversions and Promotions

用 Java 编程语言编写的每个表达式都有一个类型 可以从表达式的结构和类型推导出来 表达式中提到的文字、变量和方法。 但是,可以在上下文中编写表达式,其中 表达式的类型不合适。在某些情况下,这会导致 在编译时出错。在其他情况下,上下文可能能够 接受与表达式类型相关的类型; 作为 方便,而不是要求程序员指明类型 显式转换,Java 编程语言执行 从表达式类型到类型的隐式转换 可以接受它的周围环境

从这里,我们知道即使程序员没有指明类型转换,编译器也会接受特定的表达式。这就是为什么下面的代码不会在编译时引发错误的原因。

int i = new Integer(3);
Integer j = 3;

Chapter 5. Conversions and Promotions 5.1.7. Boxing Conversion

...在运行时,装箱转换进行如下:

如果 p 是布尔类型的值,则装箱转换将 p 到类和布尔类型的引用 r 中,这样 r.booleanValue() == p ...

Chapter 5. Conversions and Promotions 5.1.8. Unboxing Conversion

...在运行时,拆箱转换过程如下:

如果 r 是布尔类型的引用,则拆箱转换转换为 r 进入 r.booleanValue() ...

这正是运行时发生的事情。

【讨论】:

    【解决方案2】:

    自动装箱和拆箱是编译时过程。

    我们可以通过如下所述的小测试来验证:

    创建一个名为“Crap”的 Java 项目。在其中,创建一个包含以下内容的 .java 文件:

    public class Crap {
    
        private Boolean crap;
    
        public Boolean getCrap() {
            return crap;
        }
    
        public void setCrap(Boolean crap) {
            System.out.println("lol.. this is crap!!");
            this.crap = crap;
        }
    }
    

    构建此项目并导出为 jar 文件,例如 crap.jar。

    现在再创建一个名为“Junk”的 Java 项目。将 crap.jar 文件添加到该项目的类路径中,然后创建一个包含以下内容的 .java 文件:

    public class Junk {
    
        public static void main(String[] args) {
            Crap crap = new Crap();
            crap.setCrap(true);
        }
    }
    

    现在,构建 Junk 项目,并将 Junk.java 作为 Java 应用程序运行。它将成功运行,输出将是

    大声笑..这是废话!

    现在,修改 Crap.java,将 Boolean crap 修改为 boolean 以及相应的 getter 和 setter。代码如下所示:

    public class Crap {
    
        private boolean crap;
    
        public boolean getCrap() {
            return crap;
        }
    
        public void setCrap(boolean crap) {
            System.out.println("lol.. this is crap!!");
            this.crap = crap;
        }
    }
    

    再次构建这个项目并将其导出为 crap.jar。将此 crap.jar 文件放入 Junk 项目的类路径中(并从其类路径中删除较早的 jar 文件)。

    现在,如果您尝试将 Junk.java 作为 java 应用程序运行,您将得到以下堆栈跟踪:

    Exception in thread "main" java.lang.NoSuchMethodError: crap.Crap.setCrap(Ljava/lang/Boolean;) at junk.Junk.main(Junk.java:9)
    

    【讨论】:

      【解决方案3】:

      嗯,它说编译器会这样做。所以它发生在编译时。

      这是确保 Java 的静态类型安全所必需的。

      【讨论】:

        【解决方案4】:

        Tutorials 中,它说:

        List<Integer> li = new ArrayList<>();
        for (int i = 1; i < 50; i += 2)
            li.add(i);
        

        ...编译器不会产生错误,因为它从i 创建了一个Integer 对象并将该对象添加到li。因此,编译器在运行时将之前的代码转换为以下代码:

        List<Integer> li = new ArrayList<>();
        for (int i = 1; i < 50; i += 2)
            li.add(Integer.valueOf(i));
        

        因此,通过在代码中插入方法调用和强制转换(由编译器)实现的转换发生在编译时,但在运行时处理。

        【讨论】:

          猜你喜欢
          • 2021-04-30
          • 1970-01-01
          • 2011-01-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-15
          相关资源
          最近更新 更多