Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Java inheritance work when inner classes are involved

I am having trouble understanding how inheritance works in Java when inner classes are present. I'm currently working on something where a child class needs to slightly change the functionality of the inner class of it's parent. I've come up with an simpler, analagous example below.

I expected this code to print "I am a ChildClass.InnerClass" but instead it prints "I am a ParentClass.InnerClass". Why is this? Also, if I change the obj object in main to be of type ChildClass then the output changes to "I am a ChildClass.InnerClass". Why is this?

In general, what is the recommended way of altering the behavior of an object's parent class's inner object?

class InnerClassTest {
   //-----------------------------------------------------------------------
   // PARENT CLASS
   class ParentClass {
      public ParentClass() {
         x = new InnerClass();
      }

      InnerClass x;

      class InnerClass {
         public void speak() {
            System.out.println("I am a ParentClass.InnerClass");
         }
      }
   }

   //-----------------------------------------------------------------------
   // CHILD CLASS
   class ChildClass extends ParentClass {
      public ChildClass() {
         x = new InnerClass();
      }

      InnerClass x;

      class InnerClass extends ParentClass.InnerClass {
         public void speak() {
            System.out.println("I am a ChildClass.InnerClass");
         }
      }
   }

   //-----------------------------------------------------------------------
   // MAIN
   public static void main(String[] args) {
      ParentClass obj = (new InnerClassTest()).new ChildClass();
      obj.x.speak();
   }
}
like image 968
martega Avatar asked Oct 23 '12 23:10

martega


1 Answers

Variable are not "overriden" as methods are.

In your call, you expected x to be the Child's one but it isn't because x is a variable, not a method.

But pay attention: Your reference type is ParentClass so obj.x points to the ParentClass's InnerClass attribute even though the real instance behind parentClass is a ChildClass!

In order to display your expected sentence, you have to change the type reference to ChildClass:

public static void main(String[] args) {
      ChildClass obj = (new InnerClassTest()).new ChildClass();
      obj.x.speak();
}

To better understand the concept, try to define a method in both ParentClass and ChildClass classes:

public InnerClass getInnerClass(){
  return x;
}  

and make x private.

so that "override concept" applies.

Your final call would be in this case:

ParentClass obj = (new InnerClassTest()).new ChildClass();
obj.getInnerClass().speak();

To alter the behavior of the inner classes, think of Template method pattern or better: Strategy pattern (since more respectful of DIP)

like image 175
Mik378 Avatar answered Oct 13 '22 14:10

Mik378