Question

When I tried to understand how to work with collections in java, I realised that I don't understand how polymorphism works for inner classes.

Simple code example:

 class Parent {
    public static void main(String[] args) {
        new Parent().newInnerClass().myMethod();
        new Child().newInnerClass().myMethod();
    }

    public I newInnerClass() {
        return new InnerClass();
    }

    private final class InnerClass implements I {

        @Override
        public void myMethod() {
            System.out.println("parent inner class");
            foo();
        }
    }

    public void foo() {
        System.out.println("foo from parent");
    }


}

class Child extends Parent {
    public void foo() {
        System.out.println("foo from child");
    }
}

interface I {
    void myMethod();
}

result:

parent inner class
foo from parent
parent inner class
foo from child

Therefore first link affects the third method invocation. It is surprising to me.

Initially I thought that needed methods selected accordind to the link. But new Parent().newInnerClass() and new Child().newInnerClass() are links to InnerClass from Parent.

Can you clarify my misunderstanding?

P.S.

If InnerClass was in Child and extended InnerClass from Parent - this behaviour wouldn't be surprising for me.

Was it helpful?

Solution

There are no special rules for polymorphism in inner classes.

Inner class differs from regular class in two things:

  • Inner class holds an implicit reference to its containing object
  • Inner class can access private methods of its containing class (not relevant here)

That's how you can rewrite your example without inner class:

class Parent {
    ...
    public I newInnerClass() {
        return new NotInnerClass(this);
    }
    ...
}
class NotInnerClass implements I {
    private final Parent containingObject;

    public NotInnerClass(Parent containingObject) {
        this.containingObject = containingObject;
    }

    @Override
    public void myMethod() {
        System.out.println("parent inner class");
        containingObject.foo();
    }
}

This code produces the same output as your, because when you invoke

new Child().newInnerClass().myMethod();

containingObject is a Child and containingObject.foo() is a regular polymorphic call.

When you use inner class, compiler does the same thing behind the scenes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top