Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java superinterfaces runtime difference Java 8 vs Java 9

I noticed a difference in the output of the following program when run with Java 8 and 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();
}

You can run both versions of java here: https://www.jdoodle.com/online-java-compiler/

Java 8 outputs:

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 outputs:

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

But when I reorder the super-interfaces to:

interface ServiceX extends ServiceB, ServiceA<Foo> { }

Then both versions of java output:

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

I was wondering what is causing it? Is there a new java feature I am not aware of?

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

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

like image 430
Hugh Pearse Avatar asked Jan 28 '21 12:01

Hugh Pearse


People also ask

What is the difference between Java 8 and Java 9?

Java 8 applications use packages as a top-level component whereas Java 9 applications use modules as a top-level component. Each Java 9 module has only one module with one module descriptor whereas Java 8 package doesn't build multiple modules into a single module.

What new features of Java 9 10 11 Have you used recently?

Reactive Streams: Overview of reactive programming; Understanding the Java Flow API; Implementing publishers and subscribers; Implementing processors; Practical applications. New Language Features: Private methods in interfaces; Type interference; Miscellaneous improvements; Multi-version JARs.


1 Answers

The difference seems to be in the implementation of getMethod API in use which is visible by the stated 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).

While Java-8 follows up internally with interfaceCandidates.getFirst() (i.e. the order change matters here), the upgraded version seems to be working on the specific algorithm using res.getMostSpecific() before returning the method asked for.

like image 101
Naman Avatar answered Oct 19 '22 07:10

Naman