GetDeclaredMethods() ведет себя по-разному в Java 7 и Java 8
Рассмотрим следующий небольшой пример:
package prv.rli.codetest;
import java.lang.reflect.Method;
public class BreakingInterfaces {
interface Base {
BaseFoo foo();
interface BaseFoo {
}
}
interface Derived extends Base {
DerivedFoo foo();
interface DerivedFoo extends BaseFoo {
}
}
public static void main(String[] args) {
dumpDeclaredMethods(Derived.class);
}
private static void dumpDeclaredMethods(Class<?> class1) {
System.out.println("---" + class1.getSimpleName() + "---");
Method[] methods = class1.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("----------");
}
}
Если вы скомпилируете приведенный выше пример с помощью jdk1.7.0.55, результат будет следующим:
---Derived---
public abstract BreakingInterfaces$Derived$DerivedFoo BreakingInterfaces$Derived.foo()
----------
Но при использовании jdk1.8.0.25 вывод:
---Derived---
public abstract prv.rli.codetest.BreakingInterfaces$Derived$DerivedFoo prv.rli.codetest.BreakingInterfaces$Derived.foo()
public default prv.rli.codetest.BreakingInterfaces$Base$BaseFoo prv.rli.codetest.BreakingInterfaces$Derived.foo()
----------
Кто-нибудь знает, является ли это ошибкой в jdk1.8.0.25 или почему метод public default здесь появляется?
Ответы
Ответ 1
getDeclaredMethods()
ведет себя корректно здесь, так как он точно сообщает, что он нашел в классе. Если вы загружаете interface
, скомпилированный с целевым ядром Java 7 (или более старым компилятором), вы не увидите различий в выходе реализации Java 7 getDeclaredMethods()
.
Его компилятор, который ведет себя по-разному. При компиляции такого sub interface
в Java 8 будет создан мостовой метод, который не будет сгенерирован для целевого объекта Java 7, поскольку он даже невозможен для цели Java 7.
Причина, по которой методы моста создаются для интерфейсов, заключается в том, что у вас обычно больше классов реализации, чем интерфейсов, поэтому наличие моста default
bridge в интерфейсе избавляет вас от добавления этого метода моста для каждой реализации. Кроме того, он значительно упрощает создание классов лямбда, если существует только один метод abstract
и не используется метод моста.
Если иерархия interface
требует модовых методов, но не предоставляет default
s, компилятор должен сгенерировать код, используя LambdaMetafactory.altMetafactory
, а не LambdaMetafactory.metafactory
, указав каждый требуемый мостовой метод.