Java 超级接口运行时间差异 Java 8 vs Java 9
Java superinterfaces runtime difference Java 8 vs Java 9
我注意到当 运行 与 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
区别似乎在于 getMethod
API 在使用中的实现,这在规定的 documentation starting Java-9 :
中可见
Within each such subset only the most specific methods are selected.
Let method M be a method from a set of methods with same VM signature
(return type, name, parameter types). M is most specific if there is
no such method N != M from the same set, such that N is more specific
than M. N is more specific than M if:
a. N is declared by a class and M is declared by an interface; or
b. N and M are both declared by classes
or both by interfaces and N's declaring type is the same as or a
subtype of M's declaring type (clearly, if M's and N's declaring types
are the same type, then M and N are the same method).
虽然 Java-8 在内部跟进 interfaceCandidates.getFirst()
(即这里的顺序更改很重要),但升级版本似乎在返回之前使用 res.getMostSpecific()
处理特定算法要求的方法。
从问题正文中移出答案:
根本原因是 java 类型擦除在编译时创建了一个具有 return 类型“对象”的桥接方法,它不如 return 类型的具体“粘性物”。 Java 9 更新了 Class.getMethod() 的实现,从 return 第一个定义接口的实现改为 return 最具体的实现。
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 9 一起使用,就像在 Java 8.
中一样
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();
}
我注意到当 运行 与 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
区别似乎在于 getMethod
API 在使用中的实现,这在规定的 documentation starting Java-9 :
Within each such subset only the most specific methods are selected. Let method M be a method from a set of methods with same VM signature (return type, name, parameter types). M is most specific if there is no such method N != M from the same set, such that N is more specific than M. N is more specific than M if:
a. N is declared by a class and M is declared by an interface; or
b. N and M are both declared by classes or both by interfaces and N's declaring type is the same as or a subtype of M's declaring type (clearly, if M's and N's declaring types are the same type, then M and N are the same method).
虽然 Java-8 在内部跟进 interfaceCandidates.getFirst()
(即这里的顺序更改很重要),但升级版本似乎在返回之前使用 res.getMostSpecific()
处理特定算法要求的方法。
从问题正文中移出答案:
根本原因是 java 类型擦除在编译时创建了一个具有 return 类型“对象”的桥接方法,它不如 return 类型的具体“粘性物”。 Java 9 更新了 Class.getMethod() 的实现,从 return 第一个定义接口的实现改为 return 最具体的实现。
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 9 一起使用,就像在 Java 8.
中一样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();
}