【问题标题】:Java superinterfaces runtime difference Java 8 vs Java 9Java 超接口运行时差异 Java 8 与 Java 9
【发布时间】:2021-01-28 12:33:23
【问题描述】:

我注意到以下程序在使用 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();
}

您可以在此处运行两个版本的 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()

Java 9 输出:

intfMethod = public abstract Goo ServiceB.getType()
intfMethod = public abstract Goo ServiceB.getType()
intfMethod = public abstract Goo ServiceB.getType()

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

interface ServiceX extends ServiceB, ServiceA<Foo> { }

然后两个版本的java输出:

intfMethod = public abstract Goo ServiceB.getType()
intfMethod = public abstract Goo ServiceB.getType()
intfMethod = public abstract Goo ServiceB.getType()

我想知道是什么原因造成的?是否有我不知道的新 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

【问题讨论】:

    标签: java reflection java-8 overriding java-11


    【解决方案1】:

    不同之处似乎在于getMethod API 的实现,这在documentation starting Java-9 中可见:

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

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

    b. N 和 M 都由类声明 或两者都通过接口和 N 的声明类型与或 a 相同 M 的声明类型的子类型(显然,如果 M 和 N 的声明类型 是同一种类型,那么M和N是同一种方法)。

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

    【讨论】:

    【解决方案2】:

    答案来自问题主体:


    根本原因是编译时java类型擦除创建了一个返回类型为“Object”的桥接方法,它比返回类型“Goo”更不具体。 Java 9 对 Class.getMethod() 的实现进行了更新,从返回第一个定义的接口的实现改为返回最具体的实现。

    foo@bar:~$ javap ./ServiceImpl.class
    Compiled from "OrderingTest.java"
    class ServiceImpl implements ServiceX {
      ServiceImpl();
      public Foo getType();
      public java.lang.Object getType(); <== here
      public Goo getType();
    }
    

    Java 8 中的旧功能可以在 Java 9 中通过添加另一个接口来维护,该接口使用 API 覆盖通用方法,使其更具体。这将像在 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 new Foo(); }
    }
    
    interface ServiceX extends ServiceAA, ServiceB { }
    abstract class Goo { }
    class Foo extends Goo { }
    interface ServiceAA extends ServiceA<Foo> {
        @Override
        Foo getType();
    }
    interface ServiceA<S> {
        S getType();
    }
    interface ServiceB {
        @java.lang.Deprecated
        Goo getType();
    }
    

    【讨论】:

      猜你喜欢
      • 2017-11-02
      • 1970-01-01
      • 1970-01-01
      • 2021-05-25
      • 2018-03-12
      • 2012-02-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多