Java 在编译时解析静态方法

Java 在编译时解析静态方法,java,inheritance,static-methods,Java,Inheritance,Static Methods,Java编译器(几乎)总是在编译时解析静态方法,这是一个常见的事实。例如: public class Super { static void someMethod() { // Do something... } } public class Derived extends Super { // Some other methods, excluding someMethod } 测试代码: Derived derived = new Derived()

Java编译器(几乎)总是在编译时解析静态方法,这是一个常见的事实。例如:

public class Super {
    static void someMethod() {
        // Do something...
    }
}
public class Derived extends Super {
    // Some other methods, excluding someMethod
}
测试代码:

Derived derived = new Derived();
derived.someMethod();
这应该调用Super.someMethod(),对吗?它应该在编译时被解析,这样javac将生成
invokestatic Super.someMethod
,但我已经看到它生成
invokestatic-Derived.someMethod
。它为什么这样做?有没有办法改变这种行为


如果我错了,请纠正我。

让我们假设在
Super
Derived
之间有一个中间超类(称为
intermediate

编译器生成
Derived.someMethod
的原因是,您可以重新编译
Intermediate
以插入
someMethod
的实现,这将使该实现与记录的
Super
形成阴影:

public class TestSuperDerived {
    public static void main(String[] argv) {
        DerivedClass.someMethod();
    }
}
class SuperClass {
    static void someMethod() {
        System.out.println("Here!");
    }
}
class DerivedClass extends SuperClass {
    // Some other methods, excluding someMethod
}
javap输出:

C:\JavaTools>javap -c TestSuperDerived
Compiled from "TestSuperDerived.java"
public class TestSuperDerived {
  public TestSuperDerived();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #2                  // Method DerivedClass.someMethod:()V
       3: return
}
C:\JavaTools>javap-ctestsuperderived
从“TestSuperDerived.java”编译而来
公共类TestSuperDerived{
公共TestSuperDerived();
代码:
0:aload_0
1:invokespecial#1//方法java/lang/Object。“:()V
4:返回
公共静态void main(java.lang.String[]);
代码:
0:invokestatic#2//方法DerivedClass.someMethod:()V
3:返回
}

javac编译器在编译时解析所有方法引用,包括查找方法和检查其签名。但是,实际的方法“绑定”是在JVM加载类或第一次调用时完成的。(为什么要更改行为?它的工作方式非常有用。)您的代码甚至不会编译。你是怎么得到那个字节码的?我已经编辑了代码来反映我对OP意图的解释。如果一个类实际上不是从任何东西派生的,那么将其称为“派生”类就没有意义@kabbi,请发布可以编译以避免误解的代码。应该注意的是,使用实例调用静态方法是一种javac“swizzle”,它与Java的工作方式无关,而纯粹是一种“方便”。编码
SomeClass someRef=new SomeClass();someRef.someStaticMethod()
完全等同于编码
SomeClass.someStaticMethod()。这与继承无关。或者您可以简单地编辑并重新编译派生以添加该方法。@HotLicks这并没有说明它生成
派生的.someMethod
的原因。它生成该方法的原因是javac从不假设编译时存在的情况是运行时将存在的情况。当前类之外的任何类都可以更改,并且生成invokesuper将导致在面对此类更改时出现不遵从行为。@HotLicks这就是我的答案所说的,具体来说。是的,我只是指出,除了您所述的应用此概念的场景之外,还有其他场景。