Monday, February 21, 2011

Local Classes

A local class is declared locally within a block of Java code, rather than as a member of a class.

Typically, a local class is defined within a method, but it can also be defined within a static initializer or instance initializer of a class. Because all blocks of Java code appear within class definitions, all local classes are nested within containing classes. For this reason, local classes share many of the features of member classes. It is usually more appropriate, however, to think of them as an entirely separate kind of inner class.
A local class has approximately the same relationship to a member class as a local variable has to an instance variable of a class.The defining characteristic of a local class is that it is local to a block of code. Like a local variable, a local class is valid only within the scope defined by its enclosing block.

Defining and Using a Local Class
// This method creates and returns an Enumeration object

public java.util.Enumeration enumerate() {
// Here's the definition of Enumerator as a local class
   class Enumerator implements java.util.Enumeration {

      Linkable current;
      public Enumerator() { current = head; }
      public boolean hasMoreElements() {  
         return (current != null); 
      }

      public Object nextElement() {
      if (current == null) 
         throw new java.util.NoSuchElementException();

      Object value = current;
      current = current.getNext();

      return value;

    }

  }

   // Now return an instance of the Enumerator class 
   //defined directly above
   return new Enumerator();
}


Features of Local Classes
Local classes have the following interesting features:

  • Like member classes, local classes are associated with a containing instance, and can access any members, including private members, of the containing class.

  • In addition to accessing fields defined by the containing class, local classes can access any local variables, method parameters, or exception parameters that are in the scope of the local method definition and declared final.

Restrictions on Local Classes
Local classes are subject to the following restrictions:
  • A local class is visible only within the block that defines it; it can never be used outside that block.

  • Local classes cannot be declared public, protected, private, or static. These modifiers are for members of classes; they are not allowed with local variable declarations or local class declarations.

  • Like member classes, and for the same reasons, local classes cannot contain static fields, methods, or classes. The only exception is for constants that are declared both static and final.

  • Interfaces cannot be defined locally.

  • A local class, like a member class, cannot have the same name as any of its enclosing classes.

  • As noted earlier, a local class can use the local variables, method parameters, and even exception parameters that are in its scope, but only if those variables or parameters are declared final. This is because the lifetime of an instance of a local class can be much longer than the execution of the method in which the class is defined. For this reason, a local class must have a private internal copy of all local variables it uses (these copies are automatically generated by the compiler). The only way to ensure that the local variable and the private copy are always the same is to insist that the local variable is final.

New Syntax for Local Classes
In Java 1.0, only fields, methods, and classes can be declared final. The addition of local classes in Java 1.1 has required a liberalization in the use of the final modifier. It can now be applied to local variables, method parameters, and even the exception parameter of a catch statement. The meaning of the final modifier remains the same in these new uses: once the local variable or parameter has been assigned a value, that value cannot be changed.
Instances of local classes, like instances of member classes, have an enclosing instance that is implicitly passed to all constructors of the local class. Local classes can use the same this syntax as member classes, to refer explicitly to members of enclosing classes. Because local classes are never visible outside the blocks that define them, however, there is never a need to use the new and super syntax used by member classes to specify the enclosing instance explicitly.

Scope of a Local Class
In discussing member classes, we saw that a member class can access any members inherited from superclasses and any members defined by its containing classes. The same is true for local classes, but local classes can also access final local variables and parameters. The following code illustrates the many fields and variables that may be accessible to a local class:

class A { protected char a = 'a'; }
class B { protected char b = 'b'; }

public class C extends A {
   // Private fields visible to local class
    private char c = 'c';    
    public static char d = 'd';

    public void createLocalObject(final char e)
    {

        final char f = 'f';
       // i not final; not usable by local class
        int i = 0;                  

       class Local extends B
       {

        char g = 'g';
        public void printVars()
        {

         // All of these fields and variables are accessible 
         //to this class

        // (this.g) g is a field of this class
            System.out.println(g);  
        // f is a final local variable
            System.out.println(f);  
        // e is a final local parameter
            System.out.println(e);  
        // (C.this.d) d -- field of containing class
            System.out.println(d);  
        // (C.this.c) c -- field of containing class
            System.out.println(c);  
        // b is inherited by this class
            System.out.println(b);  
        // a is inherited by the containing class
            System.out.println(a);  

        }

    }
    
    Local l = new Local(); // Create an instance of the local class
    l.printVars();   // and call its printVars() method. 

  }

}


Local Classes and Local Variable Scope
A local variable is defined within a block of code, which defines its scope. A local variable ceases to exist outside of its scope. Java is a lexically scopedlanguage, which means that its concept of scope has to do with the way the source code is written. Any code within the curly braces that define the boundaries of a block can use local variables defined in that block.


Lexical scoping simply defines a segment of source code within which a variable can be used. It is common, however, to think of a scope as a temporal scope--to think of a local variable as existing from the time the Java interpreter begins executing the block until the time the interpreter exits the block. This is usually a reasonable way to think about local variables and their scope.
The introduction of local classes confuses the picture, however, because local classes can use local variables, and instances of a local class can have a lifetime much longer than the time it takes the interpreter to execute the block of code. In other words, if you create an instance of a local class, the instance does not automatically go away when the interpreter finishes executing the block that defines the class, as shown in the following code:
public class Weird {

  // A static member interface used below

  public static interface IntHolder { public int getValue(); }

  public static void main(String[] args) {     

// An array to hold 10 objects
  IntHolder[] holders = new IntHolder[10];
  
  for(int i = 0; i < 10; i++) {   // Loop to fill the array up
    final int fi = i;              // A final local variable
// A local class
    class MyIntHolder implements IntHolder { 

    public int getValue() { return fi; }  // It uses the final variable

    }

  holders[i] = new MyIntHolder(); // Instantiate the local class

}

  // The local class is now out of scope, so we can't use it. But
  // we've got ten valid instances of that class in our array. The 
  //local variable fi is not in our scope here, but it is still 
  //in scope for the getValue() method of each of those ten objects.
  //So call getValue() for each object and print it out. 
  //This prints the digits 0 to 9. 

    for(int i = 0; i < 10; i++) 
        System.out.println(holders[i].getValue());

  }

}

The behavior of the previous program is pretty surprising. To make sense of it, remember that the lexical scope of the methods of a local class has nothing to do with when the interpreter enters and exits the block of code that defines the local class. Here's another way to think about it: each instance of a local class has an automatically created private copy of each of the final local variables it uses, so, in effect, it has its own private copy of the scope that existed when it was created.

No comments:

Post a Comment

Chitika