Java 超级接口运行时差异 Java 8 与 Java 9

Hug*_*rse 8 java reflection overriding java-8 java-11

当使用 Java 8 和 Java 9 运行时,我注意到以下程序的输出有所不同。

import java.lang.reflect.Method;
public class OrderingTest {
    public static void main(String[] args) {
        ServiceImpl service = new ServiceImpl();
        for (Method method : service.getClass().getMethods()) {
            for (Class<?> anInterface : method.getDeclaringClass().getInterfaces()) {
                try {
                    Method intfMethod = anInterface.getMethod(method.getName(), method.getParameterTypes());
                    System.out.println("intfMethod = " + intfMethod);
                } catch (NoSuchMethodException e) { }
            }
        }
    }
}

class ServiceImpl implements ServiceX {
    @Override
    public Foo getType() { return null; }
}

interface ServiceX extends ServiceA<Foo>, ServiceB { }
abstract class Goo { }
class Foo extends Goo { }

interface ServiceA<S> {
    S getType();
}
interface ServiceB {
    @java.lang.Deprecated
    Goo getType();
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处运行两个版本的 java:https : //www.jdoodle.com/online-java-compiler/

Java 8 输出:

intfMethod = public abstract java.lang.Object ServiceA.getType()
intfMethod = public abstract java.lang.Object ServiceA.getType()
intfMethod = public abstract java.lang.Object ServiceA.getType()
Run Code Online (Sandbox Code Playgroud)

Java 9 输出:

intfMethod = public abstract Goo ServiceB.getType()
intfMethod = public abstract Goo ServiceB.getType()
intfMethod = public abstract Goo ServiceB.getType()
Run Code Online (Sandbox Code Playgroud)

但是当我将超级接口重新排序为:

interface ServiceX extends ServiceB, ServiceA<Foo> { }
Run Code Online (Sandbox Code Playgroud)

然后两个版本的java输出:

intfMethod = public abstract Goo ServiceB.getType()
intfMethod = public abstract Goo ServiceB.getType()
intfMethod = public abstract Goo ServiceB.getType()
Run Code Online (Sandbox Code Playgroud)

我想知道是什么原因造成的?是否有我不知道的新 Java 功能?

Java 8 文档 https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8

Java 9 文档 https://docs.oracle.com/javase/specs/jls/se9/html/jls-8.html#jls-8.4.8

Nam*_*man 7

区别似乎在于正在getMethod使用的API的实现,这可以从 Java-9 开始的声明文档中看到:

在每个这样的子集中,只选择最具体的方法。令方法 M 是一组方法中的一个方法,具有相同的 VM 签名(返回类型、名称、参数类型)。M 是最具体的,如果没有这样的方法 N != M 来自同一个集合,这样 N 比 M 更具体。 N 比 M 更具体,如果:

一种。N由类声明,M由接口声明;或者

湾 N 和 M 都由类声明或都由接口声明,并且 N 的声明类型与 M 的声明类型相同或者是 M 的声明类型的子类型(显然,如果 M 和 N 的声明类型是相同的类型,那么 M 和 N 是相同的方法) .

虽然 Java-8 在内部跟进interfaceCandidates.getFirst()(即这里的顺序更改很重要),但升级版本似乎res.getMostSpecific()在返回请求的方法之前使用特定的算法。