【问题标题】:Java Overloading - will computation happens at compile time or runtime?Java 重载 - 计算会发生在编译时还是运行时?
【发布时间】:2014-08-08 18:47:36
【问题描述】:

下面是代码

package org.nagark;


class baseClass{

    public void callMtd(int i){
        System.out.println("integer method"+i);
    }

    public void callMtd(double d){
        System.out.println("double method"+d);
    }
}

public class OverRidingExample {

    /**
     * @param args
     */
    public static void main(String[] args) {
        baseClass bc = new baseClass();
        bc.callMtd(10/3);
    }

}

OverRidingExample 类中,我使用参数 10/3 调用 baseClass.callMtd 方法(如您在代码中所见)。由于baseClass中重载了callMtd,那么默认调用哪个版本呢?因为它是重载的方法绑定应该在编译时发生,但是 10/3 的计算可以在编译时发生吗?

【问题讨论】:

标签: java overloading


【解决方案1】:

10/33 相同,所以会调用int 版本。

int 仅在不存在 int-parametrized 方法时才会转换为 double

10/3 的计算将在编译时进行,因为它满足常量表达式的definition(感谢holger)。

方法及其完整签名(包括参数类型)总是在编译时解析。例如,如果您正在使用某个 jar 并从该 jar 中的任何类调用某个方法 methodName(String x) 并且此方法更改签名(扩大)同时将这个 jar 替换为更现代的版本为 methodName(Object x)(没问题,不是是吗?),执行将失败。

顺便说一句,如果你不确定,你可以随时查看生成的OverRidingExample.class的字节码:

$ javap -c  OverRidingExample.class 
Compiled from "OverRidingExample.java"
public class org.nagark.OverRidingExample {
  public org.nagark.OverRidingExample();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class org/nagark/baseClass
       3: dup
       4: invokespecial #3                  // Method org/nagark/baseClass."<init>":()V
       7: astore_1
       8: aload_1
       9: iconst_3
      10: invokevirtual #4                  // Method org/nagark/baseClass.callMtd:(I)V
      13: return
}

你可以看到,这里是:

  1. 没有除法,只是加载常量(我想它等于 3)
  2. 调用int-parametrized 方法。 QED

如果您不熟悉字节码,可以阅读wiki 文章。

【讨论】:

  • 这正是我写的。但可能存在一些 Java 实现,但不会那样做。
  • 有一个precise definition of compile time constants。您可以通过检查语句 byte x = 300/3; 是否将被正确接受而 byte y = 300/2; 必须被拒绝来展示编译器的行为。另一点是即使""+100/3 == ""+100/3 也必须是true 才能满足规范(并且将再次成为编译时常量,这意味着""+100/3 == ""+100/3? 1: 0switch 语句中是一个有效的case 标签……)跨度>
  • @Holger 好的,那么我的回答在某种程度上是错误的。将被修复。谢谢。
  • @Dmitry Ginzburg:原则上,编译器可以在这种非常具体的场景中发出指令进行计算,而不会产生影响。但是还有很多其他情况会有所不同。
【解决方案2】:

编译器在决定调用哪个重载方法时会查看参数的类型。你的类型是int。所以,方法签名

public void callMtd(int i)

将被使用,在编译时确定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-22
    • 2018-05-02
    • 1970-01-01
    • 2013-08-29
    • 2012-06-26
    • 1970-01-01
    • 2013-09-17
    • 1970-01-01
    相关资源
    最近更新 更多