3

Suppose the following real-life code structure:

interface I {
  I m();
}

abstract class A implements I {
  @Override
  public abstract A m(); 

  abstract class B extends A {

  }
}

The bytecode generated for B is

abstract class A$B extends A {
  <some stuff>

  public I m(); //bridge method
    Code:
       0: aload_0
       1: invokespecial #2                  // Method A.m:()LA;
       4: areturn
}

Notice the use of invokespecial instruction pointing to the abstract method A.m(). In my opinion this must lead to an AbstractMethodError at runtime according to JVM 8 specification on invokespecial:

If all of the following are true, let C be the direct superclass of the current class.

So A will be chosen as C in our example.

The actual method to be invoked is selected by the following lookup procedure.

1) If C contains a declaration for an instance method with the same name and descriptor as the resolved method, then it is the method to be invoked.

So JVM will choose the A.m().

But the Run-time Exceptions section states that:

Otherwise, if step 1, step 2, or step 3 of the lookup procedure selects an abstract method, invokespecial throws an AbstractMethodError.

So invocation of the method will end up with the error.

I'm just wondered, why does Java compiler generate such sentenced-to-fail bytecode?

P.S. I have a guess that the above bridge method will never be called at all because the eventual implementor of class A.B will override it. But then the following question appears: for what purpose does java generate this bridge method?

Holger
  • 285,553
  • 42
  • 434
  • 765
  • 1
    Interesting issue. I assume, you already noticed that this bridge method isn’t there when `B` is not a member class of `A`. You’re right in that every actual implementation having a concrete `m()` will also have a bridge method on its own, as a bonus, `A` also contains a (valid) bridge method, which makes the bridge method in `B` even more obsolete. And, as said, if `B` was a top level class, there was no such bridge method. By the way, Eclipse doesn’t generate that broken bridge method in `A$B`. – Holger Mar 03 '17 at 17:49
  • 1
    Yeap, I noticed that it works this way only under certain conditions that you precisely have mentioned. I didn't think to check it with a different compiler, so many thanks for that! After some discussions with experienced Java-programmers I'm inclined to consider this case a javac's bug, so I'm going to fill an issue for javac-team shortly. P.S. also thank you for the correction of the title – Sergei Patrikeev Mar 03 '17 at 20:40
  • This seems to be an java issue, could you please file an issue against tools/javac – Fairoz Mar 06 '17 at 14:23
  • @Fairoz: the OP already said that he is going to “fill an issue for javac-team shortly” – Holger Mar 07 '17 at 13:31

1 Answers1

0

I don't really understand what are you trying to achieve. You want to understand why the method is generated at all?

Notice the use of invokespecial instruction pointing to the abstract method A.m(). In my opinion this must lead to an AbstractMethodError at runtime

Theoretically there should be no instance of an abstract class and any subclass which is instantiated must implement all abstract methods. So the invokespecial points to the implementing subclass. Attempt to instantiate an abstract class is usually caught by the compiler.

AbstractMethodError is thrown when no implementing subclass is found, most of the time it happens when different class version is loaded as expected or with bytecode manipulation.

gusto2
  • 11,210
  • 2
  • 17
  • 36
  • 1
    'points to the implementing subclass': I'm not sure about this statement, because the invokespecial is a kind of de-virtualized method invocation (it points to a concrete class). For virtual invocation there are special instructions invokevirtual and invokeinterface which indeed are generated by the subclass – Sergei Patrikeev Mar 03 '17 at 14:04