Inner class meaning
As its name states, a class inside another class is called an Inner Class.
Inner classes share special relationship with its containing class in that it has access to all the members of outer class(even private
ones).
This is because an inner class is also a member of outer class just like other fields and methods.
Since an inner class is a class inside another class, it may also be referred as a nested class.
An inner class can be of following types.
- Normal or Regular or Nested Inner class(normally referred to as just Inner class)
- Method Local Inner class.
- Anonymous Inner class.
- Static nested class
1. Nested Inner Class
This section will dig into all the details of an inner class. For simplicity, consider the following classes
class Outer { private String outerField = "Outer"; class Inner { private String innerField = "Inner"; } }
Here Outer is the outer class and Inner is the inner class which is contained inside Outer.
Creating object of Inner class
An inner class is inside another class. Containing class is called outer class. Thus, an inner class cannot exist without outer class and the same applies to its object(or instance).
An object of inner class cannot exist without an object of outer class.
This means that for creating an instance of inner class, you need to have an instance of outer class.
Thus, object of inner class can be created by the below given method.
// first, create object of outer class Outer outerObject = new Outer(); // create object of inner class Inner innerObject = outerObject.new Inner();
As clear from the example, to create an object of inner class, an object of outer class is necessary.
There is also a short-hand method for creating inner class object.
Inner innerObject = new Outer().new Inner();
This method also requires outer class object.
Just Remember….An object of inner class cannot be created without an object of its containing (or Outer class).
Creating Inner class Object Within Outer Class
Previous example assumes that you are instantiating inner class from somewhere outside the outer class.
But, in most cases, an object of inner class is required inside the outer class only, since outer class makes use of inner class.
So how do we create an object of inner class from inside outer class?
Consider modified sample class below.
class Outer { private String outerField = "Outer"; public void createInnerClassObject() { // create an object of inner class Inner innerObject = new Inner(); } class Inner { private String innerField = "Outer"; } }
Notice the line Inner innerObject = new Inner();
.
Previously it was stated that an inner class object cannot be created without an object of outer class but the above code snippet is doing it. Confused !!!!
Above syntax is valid because it is written inside a method of outer class.
When this code is executing, there is already an instance of outer class present, which is running the method.
Always Remember, In order to create(or access) an object of inner class, there should be an instance of outer class.
To summarize,
- When an object of inner class is created from within outer class, it can be created directly as
Inner innerObject = new Inner();
. - When an object of inner class is created from outside of outer class, it needs to be created as
Inner innerObject = new Outer().new Inner();
.
When objects of outer and inner class are printed, following is the output generated:
Outer class instance : Outer@659e0bfd
Inner class instance : Outer$Inner@2a139a55
Referencing Outer Class instance, fields and methods from Inner class
An inner class is also a member of its containing class like other fields and methods.
Thus, it can access other fields and methods of outer class in the same way as other fields and methods access one another, directly.
This holds true when accessing outer class fields and methods from inner class.
But, when referring the instance of outer class, there is a difference. In order to reference the current instance of a class, this
keyword is used.
In case of inner class, using this
inside inner class refers to current instance of inner class and not its outer class.
For referencing instance of outer class from inner class, we need to add class name to this
keyword.
Thus, to reference outer class instance from inner class, use Outer.this
syntax.
Refer below example for understanding.
class Outer { private String outerField = "Outer"; public void createInnerClassObject() { // create an object of inner class Inner innerObject = new Inner(); } class Inner { private String innerField = "Outer"; public innerClassMethod() { // access outer class field System.out.println("Outer field : " + outerField); // access inner class instance System.out.println("Inner instance : " + this); // access outer class instance System.out.println("Outer instance : " + Outer.this); } } }
Output
Outer field : Outer
Inner instance :
Outer instance :
2. Method Local Inner Class
As name suggests, a class defined inside a method is a Method Local Inner Class.
Yes, it is possible.
You can define a class inside a method as shown below.
// outer class class Outer { // outer class method public void createClass() { // class inside a method class Inner { // inner class method public void innerMethod() { System.out.println("Method local inner class"); } } // inner class ends } // method ends }
Above code has a class Outer containing a method.
This method defines a class which is inside the method body, hence called method local inner class.
Notice that Inner class also has its own method definition.
Instantiating a Method local inner class
Preceding code declares a method local inner class but it does not create any object of inner class.
Now the question arises, how to create an object of method local inner class.
Since a method local inner class is defined inside a method, it is visible only inside that method and its object can also be created only inside that method.
Below code creates an object of method local inner class and calls its method.
// outer class public class Outer { // outer class method public void createClass() { // class inside a method class Inner { // inner class method public void innerMethod() { System.out.println("Method local inner class method called"); } } // inner class ends // create inner class object Inner innerObject = new Inner(); // call inner class method innerObject.innerMethod(); } // outer class method ends // Main method public static void main(String[] args) { // create object of outer class Outer outerObject = new Outer(); // call outer class method outerObject.createClass(); } }
When the above code is executed, following is the output
Method local inner class method called
This shows that when outer class method is called, it creates an object of inner class and calls the inner class method.
Method Local Inner Class : Points to Remember
Statement which creates an object of method local inner class should be written outside class body.
Thus, the line Inner innerObject = new Inner();
should come after the local class ends.
- A method local inner class can be instantiated only inside the method in which it is declared.
This makes sense since a method class is visible inside the method only, thus its object can be created inside that method only. - A method local inner class can not access the local variables of the method in which it is declared.
If it needs to access them, they should be markedfinal
.
This is applicable before java 8. - You cannot access a method local variable inside a method local inner class and then re-assign it. This will be a compiler error.
This is applicable from java 8 since versions prior to java 8 will not even allow you to access a method local variable inside the inner class. - A method local inner class can access the fields and other methods of the class to which the method containing inner class belongs.
- A method local inner class can access the
static
fields and otherstatic
methods of the class to which the method containing inner class belongs only when the containing method isstatic
.
3. Anonymous Inner Classes
Anonymous means whose name is not known. In context of java, an Anonymous class is one which has no name.
The term Anonymous class is only applicable to Inner classes since outer classes should have a name.
An Anonymous class is an inner class because it will always be defined inside another class.
Types of anonymous class in java
In actual, an anonymous class is an implementation of an already existing class or an interface which is written somewhere else but it is defined again inside another class as required.
This may sound confusing but the examples that follow will clarify the concept.
Based on whether the anonymous class is an implementation of a class or an interface, it may belong to following two categories
A. Sub-class of a class
Let’s start with an example first
// Already existing class class Website { public void printName() { System.out.println("No website till now"); } } class SearchEngine { // Notice the syntax Website w = new WebSite() { public void printName() { System.out.println("Website is codippa.com"); } }; }
In the above example, there is a class named Website which is already created.
Another class SearchEngine redefines this class, implements its method and assigns it to a reference variable which is of the same type as the actual class.
It is also possible to call the newly implemented method using this reference variable.
Remember that the newly implemented Anonymous class is a sub-class of the actual class.
It follows Polymorphism and its object can be passed anywhere the object of Website class is expected.
Go through the below example for illustration.
class Website { public void printName() { System.out.println("No website till now"); } } class SearchEngine { // Notice the syntax Website w = new WebSite() { public void printName() { System.out.println("Website is codippa.com"); } }; // Expects an instance of Website class public void getWebsite(Website web) { // call the method of Website class web.printName(); } // Main method public static void main(String[] args) { // create an object of this class SearchEngine obj = new SearchEngine(); // call its method and pass instance of Website class obj.getWebsite(obj.w); } }
Instead of pre-defining the implementation of Website class, it can be defined where required, that is while calling the getWebsite method.
Thus main method can be modified as
public static void main(String[] args) { SearchEngine obj = new SearchEngine(); // Notice the implementation of Website class as argument obj.getWebsite(new Website() { public void print() { System.out.println("Dynamic implementation"); } }); }
The above implementation is not assigned to any reference variable, it has no name and hence the name Anonymous.
B. Implementer of Interface
An anonymous class can also be defined as the implementer of an interface.
In this case, it will define the implementation of methods declared in the interface and can be passed anywhere the object of interface is expected.
Refer below example to make it clear.
interface WebInterface { // interface method declaration public void print(); } class SearchEngine { // Notice the syntax WebInterface w = new WebInterface() { // Interface method implementation public void printName() { System.out.println("Website is codippa.com"); } }; // Expects an instance of WebInterface interface public void getWebsite(WebInterface web) { // call the method of WebInterface web.printName(); } // Main method public static void main(String[] args) { // create an object of this class SearchEngine obj = new SearchEngine(); // call its method and pass instance of WebInterface obj.getWebsite(obj.w); } }
As before, implementation of interface as anonymous class can be created where required as shown below.
public static void main(String[] args) { SearchEngine obj = new SearchEngine(); // Notice the implementation of WebInterface as argument obj.getWebsite(new WebInterface() { public void print() { System.out.println("Dynamic implementation"); } }); }
new
keyword before the interface name. Anonymous class is the only place where it is possible.Polymorphism in Anonymous classes
As stated earlier, Anonymous classes follow Polymorphism.
Since they are subclasses, they should follow Polymorphism. This section will detail out how.
Consider the below class.
class Metal { public void printThickness() { System.out.println("Thick enough"); } } class MetalDriver { // Anonymous class definition Metal metal = new Metal() { public void printThickness() { System.out.println("Thick enough"); } // new method public boolean hasLustre() { return false; } }; public void printMetalDetail(Metal m) { // call method present in actual class definition. No problem!!! m.printThickness(); // call newly defined method in Anonymous class. Compiler Error!!! m.hasLustre(); } }
Above code defines a class Metal with a single method.
This class is implemented again anonymously in another class MetalDriver where a new method is added to its definition which is not present in actual class.
Now when this new method is called, the compiler complains with an error
The method hasLustre() is undefined for the type Metal.
This is because anonymous class is a subclass while the reference is of actual class(which is the parent).
Compiler could not find the new method in parent class and flags an error.
Thus, the error establishes two facts:
(i) Anonymous class is a sub-class of actual class, and
(ii) Anonymous class definitions follows Polymorphism.
Use of anonymous class
Suppose you need to call a method that takes an argument of a type which is an interface.
Now, this interface belongs to some external library and you do not have a class which implements this interface.
How will you call this method. If you pass null
, then there is a risk of run time exceptions.
Anonymous class to the rescue.
Now you can create an anonymous class which implements this interface and pass it over the method providing implementation of its methods as per your needs.
Example follows.
// Interface from external Library interface External { public void interfaceMethod(); } class CalledClass { // Method to called. Takes an argument of interface type public void toBeCalled(External e) { e.interfaceMethod(); } }
Above code has an interface with a single method and a class whose method you need to call from your code.
Method of this class takes an argument of type interface but you do not have a class which implements this interface.
If you pass null
to the method argument, it will straightaway throw a java.lang.NullPointerException
.
Have a look at how you can call this method using Anonymous class.
class CallingClass { // Main method public static void main(String[] args) { CalledClass obj = new CalledClass(); // call method using Anonymous class obj.toBeCalled(new External() { public void interfaceMethod() { // your code } }); } }
Notice the use of Anonymous interface implementation to call the method.
This is the biggest benefit of Anonymous classes.
4. Static nested class
A static class which is defined inside another class is a static nested class. It is defined just like a normal class preceded with static keyword.
Remember that there is nothing as static class, a static nested class is just a static member of its outer class.
Since it is a static member, following apply to a static nested class.
- It can be accessed by the outer class directly without having its instance.
- It can only access static members of its outer class but not its instance variables or methods.
Static nested class example
public class Outer { // static nested class static class Inner { public void innerMethod() { System.out.println("Method of static nested class"); } } public void outerMethod() { System.out.println("Method of outer class"); } public static void main(String[] args) { // access inner class directly Inner inner = new Inner(); // call nested class method inner.innerMethod(); } }
As you can see from the above example, that in order to access static nested class, an instance of outer class is not required and it can be accessed directly.
Note that object of static nested class can not access non-static members of outer class. In the above example, nested class instance can not invoke outerMethod
of outer class.
Let’s tweak in
- When a class containing inner class is compiled, then 2 class files are generated :
one for outer class and one for inner class.
Example, Outer.class and Outer$Inner.class for outer class Outer and inner class Inner respectively.. - Class file of inner class can not be directly executed using java command.
- A normal inner class can not have
static
data members or methods. - An inner class can have a constructor.
- A method local class can be instantiated only inside the method in which it is defined.
- A method local class defined in
static
method can access onlystatic
members of the enclosing class. - An anonymous class which implements an interface, can implement only one interface as opposed to normal classes which can implement many.
- An anonymous class can not extend a class and implement an interface at the same time which normal classes can.
- Anonymous class definitions end with }; (Notice the semi-colon).
- Anonymous classes which are defined as an argument while calling a method end with }); (Notice the semi-colon).
- You can not call a method on anonymous class reference which is not present in actual class.
- An inner class preceded with
static
is known as a nested class, not an inner class.