2

I have 2 interfaces, and 2 return types.

interface interfaceA {
   Publisher<String> doSomething();
}

interface interfaceB extends interfaceA {
   Flow<String> doSomething();
}

interface Publisher<T>{}
class Flow<T> implements Publisher<T>{}

So at runtime, I can see 2 methods of interfaceB.class.getMethods()

  1. public default my.package.Publisher my.package.interfaceB.doSomething()

  2. public abstract my.package.Flow my.package.interfaceB.doSomething()

Regarding the first one, it is Synthetic. (method.getModifiers() & 0x00001000 > 0) == true

Does java autogenerate this synthetic methods?

How does it work in general?

3
  • 1
    Those things are called bridge methods. They are needed because for the JVM the method type consists of all arguments and it's return type. Commented Sep 23, 2019 at 15:39
  • 1
    Possibly related: docs.oracle.com/javase/tutorial/java/generics/… Commented Sep 23, 2019 at 15:40
  • 1
    For a very in-depth talk about bridge methods you can watch this Video with Dan Heidinga and Brian Goetz: youtube.com/watch?v=kOBHtmqavXc Commented Sep 23, 2019 at 15:42

2 Answers 2

2

What you see here is called a bridge method.

To understand why this is needed, we have to look at how the JVM determines if two methods are different:

  • Every method has a name. Different name -> different method.
  • Every method has a descriptor. Different descriptor-> different method.

The descriptor contains all arguments and the return type (with generics, it's erasure).

From the JVM perspective Flow doSomething() is a different method than Publisher doSomething(), so when it is asked to do a invokeinterface call to Publisher doSomething() it won't call Flow doSomething().

This can happen if the target at the callsite is of type interfaceA:

intefaceA foo = ...;
foo.doSomething();

But from the language perspective, both methods are the same, and one overrides the other.

To restore this relationship, javac adds a bridge method with the original method type that just calls the overloaded method.

Sign up to request clarification or add additional context in comments.

Comments

0

The Java Language Specification specifies the following:

A construct emitted by a Java compiler must be marked as synthetic if it does not correspond to a construct declared explicitly or implicitly in source code, unless the emitted construct is a class initialization method

Another definition I've seen from Java Papers is:

When an enclosing class accesses a private attribute of a nested class, Java compiler creates synthetic method for that attribute.

EDIT: It was pointed out that some of what this article states applies to an older Java version (SE7), so be mindful when reading online papers.

So for example:

import static java.lang.System.out;

public class Synthetic {

  public static void main(String[] arguments) {
      Synthetic.NestedClass nested = new Synthetic.NestedClass();
      out.println("Age: " + nested.age);
  }

  private static final class NestedClass {
      
      private String myName = "Tom";

      private int age = 42;

  }

}

The compiler will create synthetic methods for every private attribute being accessed. So, it'll create synthetic method (static int access$000(Synthetic$NestedClass)) for age, but not myName

7 Comments

This example won't create any synthetic methods with Java 11+.
@JohannesKuhn the default constructor is not synthetic. So starting with JDK 11, this example will indeed not have synthetic members. This answer is wrong anyway, as it says that “NestedClass will be marked as synthetic” whereas only the generated accessor method would be marked. And the linked paper’s statement “If there is a getter method available in source then this synthetic method will not be created” is wrong as well, as the compiler will not convert a field access to a getter call.
@Johannes, regarding your statement about Java 11, I ran two tests. In the first I complied the code with Java 8 and then used the Java class file disassembler (javap) on Synthetic$NestedClass.class and for NestedClass age to de-complies to create static int access$000(Synthetic$NestedClass);. If I run the same steps but using JDK 11, the result is exactly the same. so in essence it is creating a synthetic method to access age (even it seems with Java 11).
@Holger, I can see how the statement about the getter is confusion. Did some reading on this as I've have seen that before and it turns out that it was something occurred in SE7. Similarly regarding what is marked as synthetic. Will just update the answer above accordingly. Tx (TIL)
It’s not clear why you still have the synthetic method in JDK 11. Did you use a -target or --release option, resp. an IDE setup for an older version or Eclipse’s compiler? I just verified that with the right setup, there are no synthetic accessor methods in Java 11. This also applies to the additional synthetic constructor of NestedClass.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.