Lets start out with two simple classes:
package com.michaelt.so.supers;
public class Sup {
int methodA(int a, int b) {
return a + b;
}
}
and then
package com.michaelt.so.supers;
public class Sub extends Sup {
@Override
int methodA(int a, int b) {
return super.methodA(a, b);
}
}
Compiling methodA and looking at the byte code one gets:
methodA(II)I
L0
LINENUMBER 6 L0
ALOAD 0
ILOAD 1
ILOAD 2
INVOKESPECIAL com/michaelt/so/supers/Sup.methodA (II)I
IRETURN
L1
LOCALVARIABLE this Lcom/michaelt/so/supers/Sub; L0 L1 0
LOCALVARIABLE a I L0 L1 1
LOCALVARIABLE b I L0 L1 2
MAXSTACK = 3
MAXLOCALS = 3
And you can see right there with the invokespecial method it does the lookup against the Sup class methodA().
The invokespecial opcode has the following logic:
- If C contains a declaration for an instance method with the same name and descriptor as the resolved method, then this method will be invoked. The lookup procedure terminates.
- Otherwise, if C has a superclass, this same lookup procedure is performed recursively using the direct superclass of C. The method to be invoked is the result of the recursive invocation of this lookup procedure.
- Otherwise, an AbstractMethodError is raised.
In this case, there is no instance method with the same name and descriptor int his class so the first bullet is not going to fire. The second bullet however will - there is a superclass and it invokes the super's methodA.
The compiler doesn't inline this and there is no copy of the source of Sup in the class.
However the story isn't finished yet. This is just the compiled code. Once the code hits the JVM, HotSpot can get involved.
Unfortunately, I don't know that much about it, so I will appeal to authority on this matter and go to Inlining in Java where it is said that HotSpot can inline methods (even non-final methods).
Going to the docs it is noted that if a particular method call becomes a hot spot instead of doing that lookup each time, this information can be inlined - effectively copying the code from Sup methodA() into Sub methodA().
This is done at runtime, in memory, based on how the application is behaving and what optimizations are necessary to speed up performance.
As stated in HotSpot Internals for OpenJDK "Methods are often inlined. Static, private, final, and/or "special" invocations are easy to inline."
If you dig into the options for the JVM you will find an option of -XX:MaxInlineSize=35
(35 being the default) which is the maximum number of bytes that can be inlined. I'll point out that this is why Java likes to have lots of little methods - because they can be easily inlined. Those small methods become faster when they are called more because they can be inlined. And while one can play with that number and make it bigger it may cause other optimizations to be less effective. (related SO question: HotSpot JIT inlining strategy which points out a number of other options to peek at the internals of inlining that HotSpot is doing).
So, no - the code is not inlined at compile time. And, yes - the code could very well be inlined at runtime if performance optimizations warrant it.
And all of what I've write about HotSpot inlining only applies to HotSpot JVM distributed by Oracle. If you look at wikipedia's list of Java virtual machines there are many more than just HotSpot and the way those JVMs handle inlining can be completely different than what I've described above. Apache Harmony, Dalvik, ART - things may work differently there.