Java 在编译时解析静态方法
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()
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这就是我的答案所说的,具体来说。是的,我只是指出,除了您所述的应用此概念的场景之外,还有其他场景。