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, указав каждый требуемый мостовой метод.