Search code examples
javamultiple-inheritanceundefined-behaviorauto-value

Multiple inheritance quagmire - which class is instantiated?


Supposing I have the following classes:

abstract class A {
    static abstract class _Foo {}
}

class B extends A {
    static void doSomething() {
        System.out.println(C.saySomething());
    }

    static _Foo getInner() {
        return new C._Foo();
    }

    static abstract class _Foo extends A._Foo {}
}

final class C extends D {
    static String saySomething() {
        return "Something";
    }
}

abstract class D {
    static class _Foo extends B._Foo {
        public int value() {
            return 42;
        }
    }
}

To provide some context:

  • All of these classes reside in the same package.
  • Class C and D are generated at compile time
  • Class A as well as C are never instantiated; they simply provide some behaviour for class B
  • Class B is the only one that is actually used.
  • Class D is unknown until after compile time, which is why we are only using C in B.

This is similar to what one might expect when working with google autovalue


My question is with regards to the getInner function in B:

  1. Which _Foo will be instantiated at the line return new C._Foo();? The _Foo in D or the one in A?
  2. Is this undefined behaviour as to which gets instantiated or is it documented? Please provide documentation if possible
  3. How is the order determined?

The last question is just as an FYI, I'm mostly interested in the first two.

Thanks for your help.


Solution

  • To answer your three questions...

    1. An instance of the _Foo in D will be returned from new C._Foo().
    2. No, it isn't; the _Foos are "members" of the classes they are declared in, so they are inherited much like variables. (In this case, like static variables.) [Spec] (https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.2). (This is the best documentation I could muster up.)
    3. The order is determined by what is immediately inherited by class C. Since C extends D, C will inherit whatever D has (i.e. D._Foo). If D didn't declare a class called _Foo, then D would inherit B's _Foo, and then C would inherit that.

    Hope this helps. :)