Saturday, April 4, 2015

What are nested classes and why do we need them?

If a class A is declared inside another class B then that class A is a nested class. It is a member of enclosing class. If a nested class is marked static then it is called static nested class and if it not then it is called non-static nested class or inner class.

There is nothing called top level static class or static inner class. We only have static nested class.

Why do we need nested class?
As per Oracle's official page:
  1. If a class is useful to only one other class then it seems logical to embed this class as a nested class. For example if a class RedBlackNode (represents node of a Red Black Tree) is used only by class RedBlackTree then it makes sense to make RedBlackNode a nested class in the class RedBlackTree.So it is a  way of logically grouping classes that are only used in one place.
  2. A nested class increases encapsulation. Consider a class A whose members are declared private, but class B needs to access them. In that case we can hide class B in A and B can access members of A in spite of the fact that they are private. Also B can be hidden from outside world when declared private.
  3. It can lead to more readable and maintainable code.
A static nested class  interacts with the instance members of its outer class (and other classes) just like any other top-level class. In effect, a static nested class is behaviourally a top-level class that has been nested in another top-level class for packaging convenience.

Is nested class violation of encapsulation?
Some developers feel that nested class is an extreme violation of nested class. IMO this feature is safe if it is used safely. It is not a violation of encapsulation and does not violate programming principle. As I mentioned above nested class B (when declared private) is hidden from outside world and it needs to be part of class A in some ways, also members of class A are still private, so IMO it is perfectly fine and follows Single Responsibility Principle. If you are not sure whether you need a nested class or not then I believe it is better to avoid them, but if you really need them then it is fine to use them.

How do we use static nested class and non-static nested class (inner class)?
Static nested classes are always accessed using the enclosing class's name.
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

An instance of inner class (non-static class) can exist only with in an instance of Outer class.
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

Types of Non-static nested class (Inner Class)
There are two types: anonymous and local. We generally use an anonymous class (class with no name) when we create an instance of a class with some overloading of a method, without having to subclass a class. We can simply instantiate anonymous inner class without making a separate class. The classical example of anonymous class is initializing an anonymous class for Runnable interface:
Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("New Thread started.");
        }
    });

IMO, after Java 8 it makes more sense to make use of Lambda expression in such places to replace anonymous class as below:
Thread thread = new Thread(() -> System.out.println("New Thread started"));

Another type is local class. Local classes are classes that are defined in a block, which is a group of zero or more statements between balanced braces. We typically find local classes defined in the body of a method.
public class ValidateUser {
    public void validateEmails(String emailId, String alternativeEmailId) {

        final int emailIdLength = 20;

        class Email {

            String formattedEmail;

            Email(String email) {
                 if(email.length() == emailIdLength) 
                    formattedEmail = email;
                else
                    formattedEmail = null;
            }

            public String getFormattedEmail() {
                return formattedEmail;
            }

            // Valid in JDK 8 and later
            public void printOriginalEmailId() {
                System.out.println("Original email id is: " + emailId);
            }

        }

        Email email = new Email(emailId);
        if(email.getFormattedEmail() == null) {
            System.out.println("Email is invalid");
        }

        Email alternativeEmail = new Email(alternativeEmailId);
        if(alternativeEmail.getFormattedEmail() == null) {
            System.out.println("Alternative email is invalid");
        }
        
    } // method validateEmails ends here.
}

In the above example method validateEmails validates the emails provided by the user. It defines a local inner class Email to represent the email-id for a user. A local class has access to members of enclosing class. It also has access to local variables that are declared final. In the above example field emailIdLength is final and can be accessed in the constructor of the local class Email.

However starting in Java 8 there are two changes:
  1. A local class can access local variables and parameters of the enclosing block that are final or effectively final. A variable or parameter whose value is never changed after it is initialized is effectively final. Suppose the variable emailIdLength is not final and its value is changed in the constructor of local class Email, in that case this variable is not effectively final and compiler will complain.
  2. If we declare the local class in a method it can access the parameters of the enclosing method. In the above example the method printOriginalEmailId was able to access the method parameter emailId.
Actually anonymous classes are like local classes except that they do not have a name. We should use them if you need to use a local class only once.

Should I always mark a nested class static?
As Jon Skeet points out, it is a better idea if we need a nested class then to start with a static nested class and then decide if it really needs to be non-static (inner class) based on the usage. Whenever we see an inner class we need to decide whether we really need it with extra complexity and implicit (rather than explicit and more clean) reference to the outer containing class?

If an instance of inner class is strongly referenced then the outer instance is strongly referenced too. This can lead to some confusion when the outer instance is not garbage collected even though it appears that nothing references it. We must remember that an inner class maintains an implicit reference to the instance of outer class.


How to figure out if we need an inner class (non-static nested class) ?
The point to note is: Inner classes are not allowed to have static methods or fields. If we feel that we are passing a lot of stuff in the constructor of a top level class then it is an hint that we can make use of an inner class. An inner class can see all the fields of the outer class, it means we don't have to deal with the outer class fields as if they come from an outer class.

Difference between static nested class and non-static nested (inner class) class

Static Nested classNon-static nested class (Inner class)
Does not need instance of outer class as it is not associated with any instance of outer class.Needs instance of outer class for initialization.
Uses static keyword so it means it is static member of the outer class and can be accessed like that.Not a static member and every instance of inner class needs an implicit reference to instance of outer class.
Nested classes can be imported using static imports in Java.Not applicable.
Should be preferred for obvious reasons

Can we mark the nested classes final?
First of all we need to understand that static keyword can only be applied to a nested class and not to outer class. If we make anything final then it becomes constant, something that is final value and cannot be changed any further by any means. If a class is final then it simply means it cannot be inherited. So if we mark a nested class (static or non-static) final then it cannot be inherited, like any regular final class.

Can we extend nested class (static or inner)?
Yes we can extends both of them. Consider the following class which contains one static nested class and one inner class.
public class OuterClass {
    static class StaticNestedClass {
        void display() {
            System.out.println("Inside StaticNestedClass");
        }
    }
    class InnerClass {
        void display() {
            System.out.println("Inside InnerClass");
        }
    }
}

The following class extends Outerclass and its nested class also extends respective nested classes:
public class OuterClassDerivedClass extends OuterClass{
    static class StaticNestedDerivedClass extends OuterClass.StaticNestedClass {
        @Override
        void display() {
            System.out.println("Inside StaticNestedDerivedClass");
        }
    }
    class InnerDerivedClass extends OuterClass.InnerClass {
        @Override
        void display() {
            System.out.println("Inside InnerDerivedClass");
        }
    }
}

Now we can test these classes as:
public class InheritanceTest {
    public static void main(String[] args) {
        OuterClass outerClass = new OuterClass();
        OuterClass.InnerClass innerClass = outerClass.new InnerClass();
        innerClass.display();
        OuterClass.StaticNestedClass staticNestedClass = new OuterClass.StaticNestedClass();
        staticNestedClass.display();

        OuterClassDerivedClass outerClassDerivedClass = new OuterClassDerivedClass();
        OuterClassDerivedClass.InnerDerivedClass innerDerivedClass = outerClassDerivedClass.new InnerDerivedClass();
        innerDerivedClass.display();
        OuterClassDerivedClass.StaticNestedDerivedClass staticNestedDerivedClass = new OuterClassDerivedClass.StaticNestedDerivedClass();
        staticNestedDerivedClass.display();
    }
}

As expected the output will be:
Inside InnerClass 
Inside StaticNestedClass 
Inside InnerDerivedClass 
Inside StaticNestedDerivedClass

Can a Java File contain more than one public class?
A Java file can contain only one public class except for public nested classes. Check the class below:
public class Sample {
    public class InnerClassOne {
        public void display() {
            System.out.println("In class innerClassOne");
        }
    }
    public class InnerClassTwo {
        public void display() {
            System.out.println("In class innerClassTwo");
        }
    }
    static public class StaticNestedClassOne {
        public void display() {
            System.out.println("In class StaticNestedClassOne");
        }
    }
    static public class StaticNestedClassTwo {
        public void display() {
            System.out.println("In class StaticNestedClassTwo");
        }
    }
}

This can be tested as:
Sample sample = new Sample();
Sample.InnerClassOne innerClassOne = sample.new InnerClassOne();
Sample.InnerClassTwo innerClassTwo = sample.new InnerClassTwo();

Sample.StaticNestedClassOne staticNestedClassOne = new Sample.StaticNestedClassOne();
Sample.StaticNestedClassTwo staticNestedClassTwo = new Sample.StaticNestedClassTwo();

innerClassOne.display();
innerClassTwo.display();
staticNestedClassOne.display();
staticNestedClassTwo.display();

Can a nested class extend its outer class itself?
Yes it can. If we look inside the class Arc2D in java.awt.geom package, we will notice that it has static nested class Float and Double which extend the outer class itself.
public abstract class Arc2D extends RectangularShape {
  public static class Float extends Arc2D implements Serializable { .. }
  public static class Double extends Arc2D implements Serializable { .. }
}

This is done to logically group the classes and their logic. If a user wishes to use abstract class Arc2D then it is helpful to find the implementations that they can use in the class itself.

In the similar way a non-static nested class or inner class can also extend its own outer class.But why would we want an inner class to extend its outer class?  For example we can have an outer class Car which can have an inner class Wheel and every instance of Car must be having an instance of Wheel. Now it does not make conceptual sense for an inner class to extend its outer class. IMO that would be a problematic design and should be avoided.

References:
https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
http://mindprod.com/jgloss/nestedclasses.html#INHERITANCE

3 comments:

Unknown said...

Also at DZ: http://java.dzone.com/articles/what-are-nested-classes-and

Anonymous said...

"There is nothing called top level static class or static inner class. We only have static nested class."

Do you know why there is no "top level static class"? In fact there is no word called "top level static class". I think every knows this and your using this word will make people more confused.

Unknown said...

I meant you cannot mark top level class static.