11

Class Sub is a subclass of class Sup. What does that mean practically? Or in other words, what is the practical meaning of "inheritance"?

Option 1: The code from Sup is virtually copied to Sub. (as in 'copy-paste', but without the copied code visually seen in the subclass).

Example: methodA() is a method originally in Sup. Sub extends Sup, so methodA() is (virtually) copy-pasted to Sub. Now Sub has a method named methodA(). It is identical to Sup's methodA() in every line of code, but entirely belongs to Sub - and doesn't depend on Sup or is related to Sup in any way.

Option 2: The code from Sup isn't actually copied to Sub. It's still only in the superclass. But that code can be accessed through the subclass and can be used by the subclass.

Example: methodA() is a method in Sup. Sub extends Sup, so now methodA() can be accessed through Sub like so: subInstance.methodA(). But that will actually invoke methodA() in the superclass. Which means that methodA() will operate in the context of the superclass, even if it was called by the subclass.

Question: Which of the two options is really how things work? If none of them is, than please describe how these things actually work.

  • This is easy to test for yourself - write the code, examine the class files (even a checksum would do it), modify the super class, compile again, look at the class files again. You may also find reading Chapter 3. Compiling for the Java Virtual Machine of the JVM specification to be helpful in understanding (especially section 3.7). – user40980 Apr 15 '14 at 20:38
  • @MichaelT "virtually copied" is the keyword. Also, even if the code was literally being copied, this might only happen after class loading. – user7043 Apr 15 '14 at 20:47
  • @delnan it would be curious if Hotspot (or other runtime optimizers) would inline the code at some point, but that becomes an implementation detail of the JVM that may differ from one JVM to another and so couldn't be answered correctly. The best that can be done is looking at the compiled bytecode (and the invokespecial opcode usage which describes what actually happens) – user40980 Apr 15 '14 at 20:52
14

Option 2.

The bytecode is referenced dynamically at runtime: this is why, for example, LinkageErrors occur.

For example, assume you compile two classes:

public class Parent {
  public void doSomething(String x) { ... }
}

public class Child extends Parent {
  @Override
  public void doSomething(String x) {
    super.doSomething(x);
    ...
  }
}

Now modify and recompile the parent class without modifying or recompiling the child class:

public class Parent {
  public void doSomething(Collection<?> x) { ... }
}

Finally, run a program that uses the child class. You will receive a NoSuchMethodError:

Thrown if an application tries to call a specified method of a class (either static or instance), and that class no longer has a definition of that method.

Normally, this error is caught by the compiler; this error can only occur at run time if the definition of a class has incompatibly changed.

| improve this answer | |
8

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.

| improve this answer | |
1

the code is not copied, it is accessed by reference:

  • the subclass references its methods and the superclass
  • the superclass references its methods

compilers may optimize how this is represented/executed in memory, but that's basically the structure

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.