HelpEzee

Friday, July 27, 2012

Inner Classes in java


Inner classes, also called Nested Classes, are nothing but classes that are defined within other classes. The nesting is a relationship between classes, not objects.
Inner classes have clearly two benefits, name control & access control. In Java, this benefit is not as important because Java packages give the name control.
Inner classes may be defined with following access modifiers: public, protected, private, or with default package access.
The syntax for inner class is as follows:
[modifiers] class OuterClassName {
    code...
    [modifiers] class InnerClassName {
        code....
    } }


Inner Class:

Following properties can be noted about Inner classes:
ü  The outer class (the class containing the inner class) can instantiate as many number of inner class objects as it wishes, inside it’s code.
ü  If the inner class is public & the containing class as well, then code in some other unrelated class can as well create an instance of the inner class.
ü  can accept any accessibility modifiers
ü  they can be instantiated only in the context of an instance of the parent class
ü  can access all members of the enclosing class
ü  if a member in the inner class masks a member in the outer class (name collision) the inner class still has access to the outer class members: OuterClass.this.member
ü  if the inner class is public it can be instantiated from outside the outer class only using an instance of the outer class: outerInstance.new Inner()
ü  inner classes can be abstract or final
ü  hierarchies of inner classes can be created inside the outer class or inside classes that extend the outer class
ü  When inner classes are kept accessible only to the outer classes and their derived classes the syntax is pretty clear and the benefits for the design are clarity and better encapsulation. On the other hand, when inner classes are public, they can be used in surprising ways and the syntax starts to become less comprehensible. While there are creative ways to use public inner classes to solve real problems, the code for sure will start to lack in clarity and maintainability.

ü  No inner class objects are automatically instantiated with an outer class object.
ü  If the inner class is static, then static inner class can be instantiated without an outer class instance, otherwise, the inner class object must be associated with an instance of the outer class.
ü  Inner class code has free access to all elements of the outer class object that contains it, by name (no matter what the access level of the elements is), if the inner class has a variable with same name then the outer class’s variable can be accesses like this:  <OuterClassName>.this.<variableName>
ü   The outer class can call even the private methods of the inner class.

Static Inner Classes:

Syntax for static inner class is as follows:
<access-specifier> class OuterClassName {
    public static class <StaticInnerClassName> { . . .  }   . . . }
For static inner classes following additional properties hold:
ü  Static members of the outer class are visible to the static inner class, whatever their access level be.
ü  Non-static members of the outer class are not available, because there is not instance of the outer class.
ü  An inner class may not have static members unless the inner class is itself marked as static.
ü  Sometimes static nested classes are not referred to as inner class at all, as they don’t require outer classes instance.
ü  A static inner class is just like any other inner class, but it does not have the reference to its outer class object that generated it.
ü  is defined as a static member of the parent class
ü  accepts all accessibility modifiers
ü  it is NOT linked to an outer instance (it can live independently)
ü  has direct access to static members of the parent class regardless of the access modifiers declared in the parent class
ü  has direct access to all members of an instance of the parent class regardless of the access modifiers declared in the parent class

public class StaticInnerClass
{
    private static int staticCounter = 0;
    private int nestedCounter = 0;

    public static class Nested1
    {
        private static int staticCounter = 0;
        private int nestedCounter = 0;

        public static class Nested2
        {
            public Nested2(StaticInnerClass t, StaticInnerClass.Nested1 tn1)
            {
                     StaticInnerClass.staticCounter++;
                      t.nestedCounter++;
                      StaticInnerClass.Nested1.staticCounter++;
                      tn1.nestedCounter++;
              }
        }

        public Nested1(StaticInnerClass t)
        {
                  StaticInnerClass.staticCounter++;
           t.nestedCounter++;
}

        public String toString()
        {
            return
                getClass().getName() + ".nestedCounter: " + nestedCounter +
                System.getProperty("line.separator") +
                getClass().getName() + ".staticCounter: " + staticCounter;
        }
    }

    public String toString()
    {
        return
            getClass().getName() + ".nestedCounter: " + nestedCounter +
            System.getProperty("line.separator") +
            getClass().getName() + ".staticCounter: " + staticCounter;
    }

    public static void main(String[] args)
    {
       StaticInnerClass t = new StaticInnerClass();
       StaticInnerClass.Nested1 nested1 = new StaticInnerClass.Nested1(t); StaticInnerClass.Nested1.Nested2 nested2 = new
StaticInnerClass.Nested1.Nested2(t, nested1);

        System.out.println(t);
        System.out.println(nested1);
}
}


There are two more types of inner classes,
Local inner classes: The local inner classes are defined within a method.
Anonymous inner classes: Anonymous inner classes are also defined with in a method but have no name.

Local Inner Classes:


Local inner classes are declared inside of a block of code. This block can be static bloc, a constructor, a method or simply a block of code surrounded with curly braces. These classes are only visible inside the enclosing bloc, but inside the block full hierarchies of classes can be developed. Local inner classes can implement any interface or extend any class as long as those are visible and extendable. On the other hand interfaces cannot be declared in a local scope.
Local inner classes can access variables declared in the enclosing block as long as they are final. When the enclosing block is a constructor or a method the final parameters of the constructor or method are also accessible, of course for reading.
Members of the enclosing class are also accessible regardless of their access modifier. Keep in mind that a class declared in a static block can only access static members of the enclosing class.
Another interesting limitation is the fact that local inner classes cannot declare static blocks. Also a local inner cannot have the same name (hide) as an enclosing class.

ü  Local classes are never declared with an access specifier (that is, public or private). Their scope is always restricted to the block in which they are declared.
ü  Local classes have a great advantage: they are completely hidden from the outside world.
ü  They can not only access the instance variables but local variables of the method (in which they are defined) as well, but the local varible has to be declared final.
Example:
public class LocalInnerClass
{
    private static String s = "outer member";
    private int a = 1;

    static
    {
        final int b = 2;
        int c = 3;
        // local inner class in a static block
        final class LocalInner
        {
            public void f()
            {
                System.out.print(getClass().getName() + " inner in ");
                System.out.println(getClass().getEnclosingClass());
                System.out.println(s);
                System.out.println("b = " + b);
                // a = 2; // error: a is not static
                // c = 4; // error: a is not final
            }
        }

        LocalInner l = new LocalInner();
        l.f();
    }

    public LocalInnerClass(final String p1, String p2)
    {
        int a = 4; // hide the class member
        final int b = 5;

        // local inner class in a constructor
        class LocalInner
        {
            final String s2 = "inner member";
            public void f()
            {
                // declare a local inner in a method of a local inner
                class InnerInner
                {
                    public void f()
                    {
System.out.print(getClass().getName() + " inner in ");
System.out.println(getClass().getEnclosingClass());
System.out.println(LocalInnerClass.this.s);
System.out.println("bbbb---"+LocalInner.this.s2);
                    }
                }

System.out.print(getClass().getName() + " inner in ");
System.out.println(getClass().getEnclosingClass());
// direct access to members of the top level class
 System.out.println("s----"+s);
 // qualified access to hidden members of the top level class
 LocalInnerClass.this.a = 2;
 // access to variables declared in the enclosing block
 System.out.println(p1);
// System.out.println(s2); // error: p2 is not final
// a = 5; // error: a is not final
System.out.println("hai b = " + b);
// use the local inner
InnerInner i = new InnerInner();
i.f();
}
}
// use the local inner
LocalInner l = new LocalInner();
l.f();
}
public static void main(String[] args)
{
LocalInnerClass o = new LocalInnerClass("final param", "non-final param");
}
}

Anonymous Inner Classes

When using local inner classes, you can often go a step further. If you want to make only a single object of this class, you don’t even need to give the class a name.
Anonymous class in Java is a class with no specified name declared and instantiated at the same time. Because it has no name it can only be used once at place of declaration. Anonymous classes implement an interface or extend a class. They cannot declare their own constructors (they don’t have a name known to the programmer) so the constructor used for instantiation is one inherited from the superclass. In the case where the the anonymous class implements an interface a no parameter constructor inherited from java.lang.Object is used.
Anonymous classes are given a name by the compiler and they are treated as local inner classes. This means that anonymous classes can access members of the enclosing class regardless of their access modifiers and they can access final variables declared in the enclosing block of code.

Such a class is called an anonymous inner class. Usually the inner class extends some interface or extends other class.
Example:
package com.shal.innerclass;


public class AnonymousInnerClass
{
    private String s = "test member access";

    public void test(final String s)
    {
        // anonymous instance as a variable
        Runnable r = new Runnable()
        {
              @Override
            public void run()
            {
                System.out.print(getClass().getName() + " inner in ");
                System.out.println(getClass().getEnclosingClass());
                System.out.println("in anonymous class 1");
                System.out.println(AnonymousInnerClass.this.s);
            }
        };

        Thread t1 = new Thread(r, "anonymous 1");

        // anonymous instance as a parameter
        Thread t2 = new Thread (new Runnable(){int a = 5;
        @Override
            public void run()
            {
                System.out.print(getClass().getName() + " inner in ");
                System.out.println(getClass().getEnclosingClass());
                System.out.println("in anonymous class 2");
                System.out.println(s);

                // anonymous instance inside another anonymous class
                Thread t3 = new Thread (new Runnable()
                {
                    @Override
                    public void run()
                    {
                       System.out.print(getClass().getName() + " inner in ");
                       System.out.println(getClass().getEnclosingClass());
                       System.out.println("in anonymous class 3");
                       System.out.println("a = " + a);
                    }

                });
                t3.start();
                try
                {
                    t3.join();
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }

        }, "anonymous 2");

        try
        {
            t1.start();
            t1.join();
            t2.start();
            t2.join();
}
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }

    public static void main(String[] args)
    {
        new AnonymousInnerClass().test("final parameter");
    }
}

ü  An anonymous inner class cannot have constructors because the name of a constructor must be the same as the name of a class, and the class has no name. Instead, the construction parameters are given to the super class constructor. In particular, whenever an inner class implements an interface, it cannot have any construction parameters. Nevertheless, you must supply a set of parentheses as in
o    new InterfaceType () { methods and data }



ü  It is recommended to refrain from using them as many programmers find too many anonymous classes hard to read.
The following table shows the types of nested classes:
Types of Nested Classes
Type
Scope
Inner
static nested class
member
no
inner [non-static] class
member
yes
local class
local
yes
anonymous class
only the point where it is defined
yes

                An inner class may not have static members unless the inner class is itself marked as static

 

Class Files Generation for Inner Classes

As we mentioned earlier each class can have more than one inner classes. Once the main class is compiled which has several inner classes, the compiler generates separate class files for each of the inner class. Have a look at below example.

// Main class
public class Main {

    // Inner class Test1
    class Test1 {    }

    // Inner class Test2
    class Test2 {   }


    public static void main(String [] args) {
     
        // Anonymous inner class 1
        new Object() {  };

        // Anonymous inner class 2
        new Object() {  };

        System.out.println("Hello World");
    }
}
Here we have a Main class which has four inner classes. Test1, Test2, Anonymous inner class 1 and Anonymous inner class 2. Once we compile this class using javac command, the compiler will generates following class files.
Main.class
Main$Test1.class
Main$Test2.class
Main$1.class
Main$2.class

No comments:

Post a Comment