We help IT Professionals succeed at work.

local and anonymous inner class

Chandramouli k
Chandramouli k asked
on
>>http://java.sun.com/docs/books/tutorial/java/javaOO/innerclasses.html
from java docs:  There are two additional types of inner classes. You can declare an inner class within the body of a method. Such a class is known as a local inner class. You can also declare an inner class within the body of a method without naming it. These classes are known as anonymous inner classes.
----

how do i convert the code given in example as inner class and anonymous inner classes?

Appreciate detailed full coding so that i can understand the difference between these three class types (inner class / local / anonymous).

Comment
Watch Question

a_b
Top Expert 2009

Commented:
Read the section on local and anonymous inner classes here - http://docstore.mik.ua/orelly/java/exp/ch05_09.htm

Give full code examples as well.
a_b
Top Expert 2009

Commented:
I meant the code gives examples also.
An name inner class is one that is declared in full _within_ another class.  If you want to expand the scope of an inner class so that it can be used more widely than just the container class.  Then you have two options.

1. Cut and paste the entire declaration from the container class's body to the end of the same file.
2. Move the entire declaration into a new file.

In each case, if the 'private' access modifier is present, it must be removed or replaced by a less restrictive modifier.
//Original code
public class ContainerClass {
  // ...
  private class InnerClass {
    // ...
  }
}

//Modified code
public class ContainerClass {
  // ...
}

class InnerClass {  //no longer an inner-class!
  // ...
}

Open in new window

An anonymous inner class is not declared in full. Actually, it is a convenient way of extending another class and does not declare a name for the sub-class.  Therefore when converting it to a named class some extra work is needed.  Often just one method of the inner class is declared in full. This method must be extracted and a class declaration completed to surround it.

My example below shows an inner class, which is an anonymous sub-class of Object, converted to a class called MyClass.
// Original code
public class ContainerClass {
  // ...

  // anonymous inner class declaration
  Object o = new Object () {
    void myMethod () { //... }
  };
}

// Modified code
public class ContainerClass { // no longer a container
  // ...

  Object o = new MyClass();
}

class MyClass {

  void myMethod () {
   //... 
  }
}

Open in new window

Chandramouli kArchitect

Author

Commented:
Thanks a_b / sailingbye

but i have understood the inner class from example given in java docs. i want to know how the same code be converted into local / anonymous class? I know bit of coding work involved in this but help is much appreciated.

attached inner class code which needs to be converted into local and anonymous class.

for me to create may take lot of time hence need your experts help.
public class DataStructure {
    //create an array
    private final static int SIZE = 15;
    private int[] arrayOfInts = new int[SIZE];
    
    public DataStructure() {
        //fill the array with ascending integer values
        for (int i = 0; i < SIZE; i++) {
            arrayOfInts[i] = i;
        }
    }
    
    public void printEven() {
        //print out values of even indices of the array
        InnerEvenIterator iterator = this.new InnerEvenIterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.getNext() + " ");
        }
    }
    
//inner class implements the Iterator pattern
    private class InnerEvenIterator {
        //start stepping through the array from the beginning
        private int next = 0;
        
        public boolean hasNext() {
            //check if a current element is the last in the array
            return (next <= SIZE - 1);
        }
        
        public int getNext() {
            //record a value of an even index of the array
            int retValue = arrayOfInts[next];
            //get the next even element
            next += 2;
            return retValue;
        }
    }
    
    public static void main(String s[]) {
        //fill the array with integer values and print out only values of even indices
        DataStructure ds = new DataStructure();
        ds.printEven();
    }
}

//The output is: 
//0 2 4 6 8 10 12 14 

Open in new window

Is this what you wanted to do?

No mention of InnerEvenIterator now.
public class DataStructure {
    //create an array
    private final static int SIZE = 15;
    private int[] arrayOfInts = new int[SIZE];
    
    public DataStructure() {
        //fill the array with ascending integer values
        for (int i = 0; i < SIZE; i++) {
            arrayOfInts[i] = i;
        }
    }
    
    public void printEven() {
        //print out values of even indices of the array
        Iterator iterator = new Iterator() {
          //start stepping through the array from the beginning
          private int next = 0;
        
          public boolean hasNext() {
            //check if a current element is the last in the array
            return (next <= SIZE - 1);
          }
        
          public int getNext() {
            //record a value of an even index of the array
            int retValue = arrayOfInts[next];
            //get the next even element
            next += 2;
            return retValue;
          }
        };

        while (iterator.hasNext()) {
            System.out.println(iterator.getNext() + " ");
        }
    }
    
    public static void main(String s[]) {
        //fill the array with integer values and print out only values of even indices
        DataStructure ds = new DataStructure();
        ds.printEven();
    }
}

Open in new window

Chandramouli kArchitect

Author

Commented:
>>sailingbye
when i compile i get following errors....

DataStructure.java:15: cannot find symbol
symbol  : class Iterator
location: class DataStructure
        Iterator iterator = new Iterator() {
        ^
DataStructure.java:15: cannot find symbol
symbol  : class Iterator
location: class DataStructure
        Iterator iterator = new Iterator() {
                                ^
2 errors
import java.util.Iterator;
Chandramouli kArchitect

Author

Commented:
Is this correct?

Iterator is a Java class and what are we trying to do here? am confused....

import java.util.Iterator;
...

Iterator iterator = new Iterator() {
...
...
}

Chandramouli kArchitect

Author

Commented:
sailingbye

I tried executing by adding import statement. am still getting 2 errors.. but different messages.
Iterator is actually an interface, not a class. What we are doing here is creating an instance of an anonymously declared class that implements the Iterator interface. Because the class is anonymous, we must declare the instance to be one of its super-classes or interfaces.

However, on closer inspection, I notice that the inner-class does not adhere to the java.util.Iterator interface. This results in further compilation errors.  I should have spotted this earlier, sorry.

So, instead of importing the java.util.Iterator, declare your own Iterator interface. I.e. append the following code to the end of the file.
interface Iterator {

  boolean hasNext();

  int getNext();
}

Open in new window

Just for completeness, the finished class, as compile tested on my JDK 1.6 set up is...


public class DataStructure {
    //create an array
    private final static int SIZE = 15;
    private int[] arrayOfInts = new int[SIZE];
    
    public DataStructure() {
        //fill the array with ascending integer values
        for (int i = 0; i < SIZE; i++) {
            arrayOfInts[i] = i;
        }
    }
    
    public void printEven() {
        //print out values of even indices of the array
        Iterator iterator = new Iterator() {
          //start stepping through the array from the beginning
          private int next = 0;
        
          public boolean hasNext() {
            //check if a current element is the last in the array
            return (next <= SIZE - 1);
          }
        
          public int getNext() {
            //record a value of an even index of the array
            int retValue = arrayOfInts[next];
            //get the next even element
            next += 2;
            return retValue;
          }
        };

        while (iterator.hasNext()) {
            System.out.println(iterator.getNext() + " ");
        }
    }
    
    public static void main(String s[]) {
        //fill the array with integer values and print out only values of even indices
        DataStructure ds = new DataStructure();
        ds.printEven();
    }
}

interface Iterator {

  boolean hasNext();

  int getNext();
}

Open in new window

Chandramouli kArchitect

Author

Commented:
sailingbye

Many thanks your effort so far...

my intention was not to create an iterator class using anonymous class but to convert a inner class to local / anonymous class. with all three source files i wuld be able to better understand how do i convert an inner class to local / anonymous class and vice versa...

Is this not possible?
I'm not sure, but by 'all three source files' I guess you mean the two you already have, named inner-class and anonymous inner-class, and a conventional external class.  Thus, I have created the conventional version here.

Things to note:
* I have changed the name InnerEvenIterator to EvenIterator, as it is no longer an inner-class.
* The accessibility of the DataStructure's fields have been broadened to allow the iterator class to access them.
* A DataStructure instance is now passed to the iterator's getNext method.


public class DataStructure {
    //create an array
    final static int SIZE = 15;
    int[] arrayOfInts = new int[SIZE];
    
    public DataStructure() {
        //fill the array with ascending integer values
        for (int i = 0; i < SIZE; i++) {
            arrayOfInts[i] = i;
        }
    }
    
    public void printEven() {
        //print out values of even indices of the array
        EvenIterator iterator = new EvenIterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.getNext(this) + " ");
        }
    }
    

    
    public static void main(String s[]) {
        //fill the array with integer values and print out only values of even indices
        DataStructure ds = new DataStructure();
        ds.printEven();
    }
}

// separate class (accessible to all classes in this package).
class EvenIterator {
    //start stepping through the array from the beginning
    private int next = 0;
    
    public boolean hasNext() {
        //check if a current element is the last in the array
        return (next <= DataStructure.SIZE - 1);
    }
    
    public int getNext(DataStructure d) {
        //record a value of an even index of the array
        int retValue = d.arrayOfInts[next];
        //get the next even element
        next += 2;
        return retValue;
    }
}

Open in new window

> my intention was ... to convert a inner class to local / anonymous class

This is what we did in comment #32970395 above.  

> Is this not possible?

If you were hoping to do it without the interface definition then you must use a class or interface from the Java API, which takes us back to java.util.Iterator. If you wanted to do something else, then I misunderstand.

Regards

Chandramouli kArchitect

Author

Commented:
Thanks for your response sailingbye...

am comfortable of creating inner classes but somewhat not good in understanding/creating local and anonymous class. I thought of learning this by comparing code of innerclass with local and anonymous class version.

>>32970395
The code i have pointed has iterator functionalites hence we were able to make use of Iterator interface to convert a inner class to anonymous class. does it mean i must have an interface when i convert an inner class to anonymous class?

i do want to know given any class A (with some instance variables/methods) inner class B (with some instance variables/methods) how to
1) convert the inner class B to local class of A
2) convert the inner class B to anonymous class of A

> does it mean i must have an interface when i convert an inner class to anonymous class?

Yes, at least an interface. A concrete class can be used, in which case the anonymous class will inherit its methods, or even an abstract class, providing the anonymous class implements all abstract methods. It is necessary, I think, so that the compiler can perform type-checking.  If, for example, the anonymous class were _not_ based upon any interface or other class, then you would have to declare your instance as an object, i.e.

Object anonymousInstance = new ...

but now this anonymous instance has type Object so the compiler has no way of verifying that subsequent operations on this type are valid. A compiler error would occur if a method call that didn't belong to Object was encountered.

I'll address 1) and 2) later...
1)  Local refers to the scope of the class within the outer class.  I.e. if the inner-class is declared inside the body of a method then the inner-class is described as local to that method, just as a variable is described as local if declared inside a method.  

// Non-local inner-class
class OuterClass {
  void classMethod () {
  }
  class InnerClass {
  }
}

// local inner-class
class OuterClass {
  void classMethod () {
    class localInnerClass {
    }
  }
}

Anonymous classes are inherently local.

Interestingly, non-local inner-classes can be declared as public and subsequently used in other classes!  E.g.

// public inner-class
public class OuterClass {
  public class InnerClass {
  }
}

The InnerClass can be instantiated (anywhere) from an instance of OuterClass:

OuterClass oc = new OuterClass();
OuterClass.InnerClass ic = new oc.InnerClass();

Although this is unusual and, in my opinion, any benefits do not justify the increased complexity of code.
2) Again, I thought we had addressed this issue but I guess we did look at the simplest of cases --- where the inner class was only used in one method.  In this case conversion to anonymous was easy, by combining the inner-class declaration with instance creation.

However, if multiple uses of the inner-class exist or if the inner-class is public, then conversion to a single anonymous class is not possible/desirable.
Chandramouli kArchitect

Author

Commented:
Many thanks sailingbye....

can i create local class this way? Is this correct way of defining local class.

// Non-local inner-class
class OuterClass {
  void classMethod_innerClass () {  //defining new method for local class
    class InnerClass {
    }
 }
 void classMethod(){
 }
}

Again, how do i create anonymous class for the above? ie) class anonymousClass.

once i get this syntax want to playarond with this. i am planning to close this question with understanding of above and create new one for accessing its methods and other code issues :)
Yes, you can create a local (named) inner-class that way.  Instances of InnerClass can only be constructed within the method 'classMethod_innerClass'.

Let us suppose that you create an instance, as follows:

class OuterClass {
  void classMethod_innerClass () {  //defining new method for _outer_ class
    class InnerClass {
    }
    InnerClass ic = new InnerClass(); //allowed
    // use ic as any other object instance ...
 }
 void classMethod(){
    InnerClass ic = new InnerClass(); //not allowed, out of scope
 }
}

If we wanted to convert InnerClass from a local (named) inner-class to a local anonymous class we combine the class declaration and instance construction, as follows:

class OuterClass {
  void classMethod_innerClass () {  //defining new method for local class
    Type ic = new Type () {
    };
    // use ic as any other object instance ...

    // Cannot create another instance of the exact same class
    // as we don't have a name for it.
 }
 void classMethod(){
 }
}

Why Type is an existing class or interface.  Clearly, this may not be appropriate if many instances of the inner-class are required.

Feel free to ask me to clarify further if necessary.
Correction (sorry, I should check before I submit):

> Why Type is an existing class or interface.

Should read: Where Type is an existing class or interface.
Chandramouli kArchitect

Author

Commented:
Please give me sometime. will work on this and confirm by this week.

Again, Many thanks for all your efforts so far.
Great, your question was useful for me too.

Creating anonymous classes is common, especially when writing event listeners for graphical user interfaces but named inner classes and especially local inner classes are less common. Hence this was a good recap for me.

Cheers.