Translate

Sunday, November 4, 2012

INNER CLASSES


INNER CLASSES

Introduction

We can declare a class inside another class such type of classes are called innerclasses.This innerclasses concept has introduced in 1.1 version as the part of event handling. By observing the utilities and functionalities of inner class slowly the programmers are using this concept even in regular coding also.

Ex1: With out existing car object there is no chance of existing wheel object. Hence we have to declare wheel class inside car class.

class car
{
   class wheel
   {
   }
}

Ex:2

A map is a collection of entry objects. With out existing Map object there is no chance of existing entry object. Hence we have to define entry interface inside map interface.

interface Map
{
   interface Entity
   {
   }
}

Based on the purpose and position of inner class all the inner classes are divided into 4 categories.

1) Normal/Regular inner classes
2) Method local inner classes
3) Anonymous inner classes
4) static nested classes

Normal/Regular inner classes

A class declared inside another class directly with out static modifier is called normal or regular inner class.

Ex:


class Outter
{
          int i;
          char ch;
          void set()
          {....}
        //similarlly i can have a class here
        Class inner
        {
            //This can have its own members also
            float f;
            void display()
          {

             }
         }//end inner class
}//end outter class

Method local inner classes:

          A regular inner class is scoped inside another class’s curly braces, but outside any method code (in other words, at the same level that an instance variable is declared). But you can also define an inner class within a method:





Ex:-

class MyExOuterClass
{
          private String x = "Outer";

         void doSomething()
         {
              class MyExInnerClass
             {
                 public void accesOuter()
                {
                      System.out.println("Outer x is " + x);
                }
            }
        }

}

What a Method-Local Inner Class Can and Cannot Do

A method-local inner class can be instantiated only within the method where the inner class is defined. In other words, no other codes running in any other method—inside or outside the outer class—can ever instantiate the method-local inner class. Like regular inner class objects, the method-local inner class object shares a special relationship with the enclosing outer class object, and can access its private or any other members. However, the inner class object cannot use the local variables of the method the inner class is in.

If you ask me, Why not? Think about it. The local variables of the method live on the stack, and exist only for the lifetime of the method. You already know that the scope of a local variable is limited to the method the variable is declared in. When the method ends, the stack frame is destroyed and the variable is gone. But even after the method completes, the inner class object created within it might still be alive on the heap if, for example, a reference to it was passed into some other code and then stored in an instance variable. Because the local variables aren’t guaranteed to be alive as long as the method-local inner class object, the inner class object can’t use them. Unless the local variables are marked final! The following code attempts to access a local variable from within a method-local inner class.

class MyExOuterClass
{
             private String x = "Outer";
             void doSomething()
            {
              String z = "local variable";
              class MyExInnerClass
              {
                 public void accesOuter()
                {
                     System.out.println("Outer x is " + x);
                     System.out.println("Local variable z is " + z);
                     // Won't Compile!
                }
              }
           }
}

Compiling the preceding code makes the compiler spew out this error message:
MyExOuterClass.java:8: local variable z is accessed from within inner class;needs to be declared final
System.out.println("Local variable z is " + z);
^

Marking the local variable z as final fixes the problem:
final String z = "local variable";

And just a reminder about modifiers within a method: the same rules apply to method-local inner classes as to local variable declarations. You can’t, for example, mark a method-local inner class public, private, protected, static, transient, and the like. For the purpose of the exam, the only modifiers you can apply to a method-local inner class are abstract and final, but as always, never both at the same time.

Anonymous inner classes:

inner classes declared without any class name at all (probably you figured out why we call it anonymous).

Anonymous Inner Classes - Type One

Check out the following code:

class Ferrari
{
    public void drive()
     {
         System.out.println("Ferrari");
      }
}

class Car
{
    Ferrari p = new Ferrari()
    {
            public void drive()
           {
                System.out.println("anonymous Ferrari");
            }
      };
}

Let’s look at what’s in the preceding code:

• We define two classes, Ferrari and Car.
• Ferrari has one method, drive().
• Car has one instance variable, declared as type Ferrari. That’s it for Car. Car has no methods.

And here’s the big thing to get. The Ferrari reference variable refers not to an instance of Ferrari, but to an instance of an anonymous (unnamed) subclass of Ferrari.


Anonymous Inner Classes and Polymorphism

Polymorphism is in play when anonymous inner classes are involved. Remember that, as in the preceding Ferrari example, we’re using a superclass reference variable type to refer to a subclass object. What are the implications? You can only call methods on an anonymous inner class reference that are defined in the reference variable type! This is no different from any other polymorphic references, for example,

class McLarenF1 extends F1Car
{
     void drive() { }
}
class F1Car
{
    void brake() { }
}
class Test
{
    public static void main (String[] args)
   {
     F1Car h = new McLarenF1();
     h.brake(); // Legal, class F1Car has an brake() method
     h.drive(); // Not legal! Class F1Car doesn't have drive()
   }
}

So on the exam, you must be able to spot an anonymous inner class that—rather than overriding a method of the superclass—defines its own new method. The method definition isn’t the problem, though; the real issue is how do you invoke that new method? The reference variable type (the superclass) won’t know anything about that new method (defined in the anonymous subclass), so the compiler will complain if you try to invoke any method on an anonymous inner class reference that is not in the superclass class definition.

Check out the following, illegal code:


class Ferrari
{
    public void drive()
    {
        System.out.println("Ferrari");
     }
}

class Car
 {
      Ferrari p = new Ferrari()
      {
         public void brake()
        {
            System.out.println("anonymous sizzling Ferrari");
         }
      public void drive()
     {
      System.out.println("anonymous Ferrari");
     }
   };

   public void popIt()
   {
      p.drive(); // OK, Ferrari has a drive() method
      p.brake(); // Not Legal! Ferrari does not have brake()
   }
}

Compiling the preceding code gives us something like,
Anon.java:19: cannot resolve symbol
symbol : method brake()
location: class Ferrari
p.brake();
^





Anonymous Inner Classes Type Two

The only difference between type one and type two is that type one creates an anonymous subclass of the specified class type, whereas type two creates an anonymous implementer of the specified nterface type. In the previous examples, we defined a new anonymous subclass of type Ferrari as follows:

Ferrari p = new Ferrari() {

But if Ferrari were an interface type instead of a class type, then the new anonymous class would be an implementer of the interface rather than a subclass of the class. Look at the following example:

interface Drivable
{
   public void drive();
}
class Car
{
    Drivable c = new Drivable()
    {
       public void drive()
       {
               System.out.println("anonymous Drivable implementer");
        }
    };
}

The preceding code, like the Ferrari example, still creates an instance of an anonymous inner class, but this time the new class is an implementer of the Drivable interface. And note that this is the only time you will ever see the syntax

new Drivable()

where Drivable is an interface rather than a non-abstract class type. Because think about it, you can’t instantiate an interface, yet that’s what the code looks like it’s doing. But of course it’s not instantiating a Drivable object, it’s creating an instance of a new, anonymous, implementer of Drivable. You can read this line:

Drivable c = new Drivable() {

as, “Declare a reference variable of type Drivable that, obviously, will refer to an object from a class that implements the Drivable interface. But, oh yes, we don’t yet have a class that implements Drivable, so we’re going to make one right here, right now. We don’t need a name for the class, but it will be a class that implements Drivable, and this curly brace starts the definition of the new implementing class.”

One more thing to keep in mind about anonymous interface implementers—they can implement only one interface. There simply isn’t any mechanism to say that your anonymous inner class is going to implement multiple interfaces. In fact, an anonymous inner class can’t even extend a class and implement an interface at the same time. The inner class has to choose either to be a subclass of a named class—and not directly implement any interfaces at all—or to implement a single interface. By directly, we mean actually using the keyword implements as part of the class declaration. If the anonymous inner class is a subclass of a class type, it automatically becomes an implementer of any interfaces implemented by the superclass.

Argument-Defined Anonymous Inner Classes

If you understood what we’ve covered so far in this chapter, then this last part will be a walk in the park. If you are still a little fuzzy on anonymous classes, however, then you should reread the previous sections.

Imagine the following scenario. You’re typing along, creating the Perfect Class, when you write code calling a method on a Class1 object, and that method takes an object of type Interface1 (an interface).

class MyComplicatedClass
{
    void do() {
    Class1 b = new Class1();
     b.doSomething(!!!);

//Actually the !!! mean nothing. We don't have any argument matching // the input required here so I put the !!! to make it logical

    }
}
interface Interface1
{
    void doSomethingElse();
}
class Class1
{
    void doSomething(Interface1 f) { }
}

No problems here, except that you don’t have an object from a class that implements Interface1, and you can’t instantiate one, either, because you don’t even have a class that implements Interface1, let alone an instance of one. So you first need a class that implements Interface1, and then you need an instance of that class to pass to the Class1 class’s doSomething() method. Knowing the smart Java programmer that you are, you simply define an anonymous inner class, right inside the argument. That’s right, just where you least expect to find a class. And here’s what it looks like:

1. class MyComplicatedClass {
2. void do() {
3. Class1 b = new Class1();
4. b.doSomething(new Interface1() {
5. public void doSomethingElse() {
6. System.out.println("Hey!!!");
7. }
8. });
9. }
10. }
11.
12. interface Interface1 {
13. void doSomethingElse();
14. }
15. class Class1 {
16. void doSomething(Interface1 f) { }
17. }

All the action starts on line 4. We’re calling doSomething() on a Class1 object, but the method takes an instance that IS-A Interface1, where Interface1 is an interface. So we must make both an implementation class and an instance of that class, all right here in the argument to doSomething(). So that’s what we do. We write

new Interface1() {

to start the new class definition for the anonymous class that implements the Interface1 interface. Interface1 has a single method to implement, doSomethingElse(), so on lines 5, 6, and 7 we implement the doSomethingElse() method. Then on line 8 more strange syntax appears. The first curly brace closes off the new anonymous class definition. But don’t forget that this all happened as part of a method argument, so the close parenthesis, ), finishes off the method invocation, and then we must still end the statement that began on line 4, so we end with a semicolon. Study this syntax! You will see anonymous inner classes on the exam, and you’ll have to be very, very picky about the way they’re closed. If they’re argument local, they end like this:
});

but if they’re just regular anonymous classes, then they end like this:
};

Static nested classes:

Actually static inner classes aren’t inner classes at all, by the standard definition of an inner class. While an inner class enjoys that special relationship with the outer class (or rather the instances of the two classes share a relationship), a static MyStaticExInnerClass class does not. It is simply a non-inner (also called “top-level”) class scoped within another. So with static classes it’s really more about name-space resolution than about an implicit relationship between the two classes.

A static MyStaticExInnerClass class is simply a class that’s a static member of the enclosing class:
class MyExOuter
{
   static class StaticInner { }
}

The class itself isn’t really “static”; there’s no such thing as a static class. The static modifier in this case says that the MyStaticExInnerClass class is a static member of the outer class. That means it can be accessed, as with other static members, without having an instance of the outer class.

Instantiating and Using Static Inner Classes

You use standard syntax to access a static MyStaticExInnerClass class from its enclosing class. The syntax for instantiating a static MyStaticExInnerClass class from a non-enclosing class is a little different from a normal inner class, and looks like this:

class MyExOuter
{
  static class MyStaticExInner
   {
      void do()
      {
          System.out.println("hi");
      }
   }
}
class Test
{
   static class B2
   {
      void goB2()
      {
            System.out.println("hi 2");
       }
   }
  public static void main(String[] args) {
  MyExOuter.MyStaticExInner n = new MyExOuter.MyStaticExInner();
  n.do();
  B2 b2 = new B2();
  b2.goB2();
 }
}
Which produces
hi
hi 2

No comments: