Pankaj
Pankaj

Reputation: 15416

Invoking constructor of a Inner class from its subclass

I am learning inner class . Out of curiosity i extended the inner class which has a parameterized constructor. But when i write super(int i) to call it the code does not compile.

class Outer{
  class Inner{
    private int a;
    Inner(int i){
     this.a=i;
    }

    public void inheritFromInner(){
      System.out.println("Inherited from inner");
    }
  }       
}

class Test extends Outer.Inner{
  Test(int r){
   super(r);// This line does not compile.
  }
}

As inner classes are part(member) of the outer class and they have to be accessed through the outer class. How the super constructor of Test class can be called.

The compile error is: No enclosing instance of type Outer is available due to some intermediate constructor invocation

Upvotes: 1

Views: 1124

Answers (3)

scottb
scottb

Reputation: 10084

The existing answers do not expound upon the differences among the kinds of member classes.

A member class is any class that is declared within another class. They are sometimes called nested classes. Of the kinds of member classes, anonymous inner classes and local classes will not be mentioned here. The remaining kinds of member classes are inner classes and static member classes.

  • Inner Class. An inner class instance must be instantiated with the context of an existing outer class instance. Inner classes contain an implicit reference to the outer class instance (a fact which can cause inner class instances to lead to memory leaks). Although uncommon, you can instantiate an inner class instance as follows:

    Outer out = new Outer();
    Outer.Inner inner = out.new Inner();
    

    Because the super() keyword must be the 1st line to execute within a subclass constructor, you would have to declare your constructor like this if it really does need to be in an inner class:

    class Test extends Outer.Inner{
        Test(Outer out, int r) {
            out.super(r);
        }
    }
    
  • Static Member Class. A static member class is declared with the modifer static in the class declaration. In almost every way that matters, a static member class is a top level class. Like top level classes (and unlike inner classes), they do not require any other object instances for instantiation. Static member class objects are commonly intantiated as:

    Outer.Inner inner = new Outer.Inner();
    

Whenever possible, you should strongly favor the use of static member classes over inner classes. Use inner classes only when your member class objects really must have a superclass instance (which should be uncommon).

Upvotes: 4

Jeff Clites
Jeff Clites

Reputation: 620

The error actually has nothing to do with that specific line of code, nor with the superclass constructor taking a parameter. You can reproduce the error with a simpler example:

class Outer {
    class Inner {
    }       
}

class Test extends Outer.Inner {
}

This gives an error such as:

Outer.java:6: error: an enclosing instance that contains Outer.Inner is required
class Test extends Outer.Inner {
^
1 error

There are two type of inner classes, non-static (the default) and static (which requires the keyword static). Static inner classes are just like top-level classes (which are always static), but non-static inner classes require an instance of their enclosing class in order to be instantiated. Since Outer.Inner is a non-static inner class, it can only be instantiated "in the context of" an instance of Outer, which means either inside of a instance method of Outer, or via code such as:

Outer outer = new Outer();
outer.new Inner();

(This syntax is not commonly encountered.)

Since Test is a top-level class, it's static, and so it can't subclass a non-static inner class, because when creating an instance via new Test(), there won't be an instance of Outer provided.

Note however that this code compiles without error:

class Outer {
    class Inner {
    }

    class Test extends Outer.Inner {
    }
}

In this case, Test is also a non-static inner class of Outer, so instances of Test must be created in the context of an instance of Outer, which satisfies the requirements of its superclass.

Of course, modifying the original code to make Inner static will also allow it to compile. In real-world code, you create a non-static inner class because you need an instance of that class to have access to the associated instance of the enclosing class. In that case, you don't have the option of making it static. But if it doesn't need such access, then you should make your inner class static (or, make it a top-level class instead).

Edit: Apparently it is possible to create a static subclass of a non-static inner class, by explicitly passing an instance of the necessary enclosing class as a constructor parameter to the subclass and invoking super() on it. See scottb's answer here.

Upvotes: 1

chengpohi
chengpohi

Reputation: 14217

You need to state your Inner class to public static

class Outer{
  public static class Inner{
    private int a;
    Inner(int i){
     this.a=i;
    }

    public void inheritFromInner(){
      System.out.println("Inherited from inner");
    }
  }       
}

class Test extends Outer.Inner{
  Test(int r){
   super(r);// This line does not compile.
  }
}

Upvotes: 1

Related Questions