2013-08-11 2 views
3

Общеизвестно, что 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. Почему это так? И есть ли способ каким-то образом изменить это поведение?

Пожалуйста, исправьте меня, если я ошибаюсь.

+0

Javac компилятор разрешает * все * метод ссылки во время компиляции, с точки зрения нахождения метода и проверки его подписи. Однако фактическое «привязка» к методу выполняется, когда класс загружается JVM или при первом вызове. –

+0

(Почему вы хотите изменить поведение? Очень полезно, как это работает.) –

+0

Ваш код даже не компилируется. Как вы получаете этот байтовый код? –

ответ

4

Предположим, что существует промежуточный суперкласс между Super и Derived (называется, скажем, Intermediate).

Причины компилятор генерирует Derived.someMethod является то, что вы можете перекомпилировать Intermediate вставить реализацию someMethod, которая будет теневой реализацией от Super.

+0

Или вы можете просто отредактировать и перекомпилировать Derived для добавления метода. –

+0

@HotLicks Это не относится к тому, почему он генерирует «Derived.someMethod» априори. –

+1

Причина, по которой он генерирует то, что javac никогда не предполагает, что ситуация, которая существует во время компиляции, такова, что будет существовать во время выполнения. Любой класс за пределами текущего класса может измениться, и генерация invokesuper вызовет несовместимое поведение перед лицом такого изменения. –

1

Для записи:

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 
} 
Смежные вопросы