| Normal Inner Classes |
|---|
|
A normal inner class is a class that is declared within the body of another class, but outside
its methods. When you compile it, you get a separate .class file, named with the name of the outer class,
plus a dollar sign, plus the name of the inner class, suffixed by .class.
Example: MyClass$MyInnerClass.class You can't run an inner class by itself from the command line by saying java MyClass$MyInnerClass. An inner class is a full-fledged member of an object, just like methods and variables are. This means, it has full access to all instance variables of the current object, even those marked private. Normally, 'this' refers to the current object. For an inner class, it's the inner class object. To access the outer class's 'this' object from within the inner class, prefix 'this' with the outer class's name. For example: MyClass.this |
|
An instance of an inner class can't exist outside an instance of an outer class, unless it's marked
'static' - which is really a top-level nested class, not an inner class.
Before using the inner non-static class, the enclosing object must first create an instance of it. An instance of the class doesn't 'automatically exist' just because it's declared, it has to be instantiated, as well. It is possible to instantiate an inner class from within a different class, according to the normal member visibility rules - ie, it must be visible to the other class. To do this, use the following syntax: MyInnerClass mic = new MyClass().new myInnerClass()If you want to prevent other classes from using your inner class, mark the inner class private - that way only the enclosing class can instantiate it. |
| Method Local Inner Classes |
|---|
|
A method-local inner class is a class that's declared within the body of a method.
It is not possible to instantiate a method-local inner class from outside the method. The class must be declared, before the variable that uses it is declared - otherwise you'll get a compiler error. A method-local inner class can access all instance variables of the current object, even those marked private. However, it cannot use the local variables of the method it is in, unless those variables are marked final! The only modifiers that can be applied to a method-local inner class, are 'static' and 'final.' |
| Anonymous Inner Classes |
|---|
|
Anonymous classes can be declared within a method, or within an argument to a method.
Anonymous classes should override one of their declare class's method, or implement an interface, otherwise you have no way to call a method on it. New methods you tack on to an anonymous class won't be callable, unless they override or implement something! The variable you assign an anonymous class to, does not refer to an instance of its class, but to an instance of an anonymous (unnamed) subclass of that class. Be sure to include the semicolon at the end of the variable assignment! This is a plain old ordinary variable assignment, despite looking like a class creation. At the end of the variable assignment wherein you create the anonymous inner class, you have a superclass reference pointing to a subclass object. You can't call any methods on the variable that you couldn't call on the superclass - that's why this works the way it does. Interfaces work the same way! Even though you normally can't instantiate an Interface, when creating an anonymous inner class, you can. It's the only time you'll see the syntax "new Comparable()". However, they can only implement one interface, or extend one class - they can't do both, or implement multiple interfaes. This is because the resulting reference variable is STILL of only the one type, so you can only call those exact methods. Finally - you can pass anonymous classes as arguments to methods, as well. Close them with a curly brace, then pretend it never happened - finish off the method call, business as usual. In otherwords, don't put a semicolon at the end of a 'argument local' anonymous class creation! Either end it with ',' and more arguments to the method call, or ); to finish off the method call. |
| Static Nested Classes |
|---|
Static nested classes can't access the variables of their enclosing class. They're really
not an inner class, at all - they are a top-level class, scoped within another class.
The only way to access their methods is through the class name of the enclosing class,
such as:
MyClass.MyStaticClass.go(); |
| Example of All Types of Inner Classes |
|---|
import java.util.*;
public class testInnerClasses {
public static void main(String[] args) {
// Create new instance of MyClass
MyClass myclass = new MyClass();
myclass.mic.Hello();
// Access inner class from outer class
MyClass.MyInnerClass mic = myclass.new MyInnerClass();
mic.Hello();
// Method local class test
myclass.MethodLocalVariableTest();
// Anonymous class implementing an interface test
List<String> lst = new ArrayList<String>();
lst.add("a");
lst.add("b");
lst.add("c");
System.out.println(lst);
Collections.sort(lst, myclass.getReverseComparator());
System.out.println(lst);
// Test passing anonymous inner classes as arguments
myclass.TestArgumentInnerClass(new MyClass().new MyInnerClass(){
void Hello() {
System.out.println("Hello from the inner class " +
"passed to the argument!");
}
}, true);
// Test static classes
MyClass.MyStaticClass msc = new MyClass.MyStaticClass();
msc.Go();
// This works too, if you're calling a static method.
MyClass.MyStaticClass.StaticGo();
}
}
class MyClass {
// Normal inner class
MyInnerClass mic = new MyInnerClass();
class MyInnerClass {
void Hello() {
System.out.println("Hello from MyInnerClass.Hello");
}
}
void MethodLocalVariableTest() {
// Method local class 'Sigh' must appear above the variables
// that declare it, otherwise a compiler error occurs -
// 'Sigh cannot be resolved to a type'.
class Sigh {
void Right() {
System.out.println("Right.\n");
}
}
Sigh sigh = new Sigh();
sigh.Right();
}
void AnonymousTest() {
// Test anonymous subclasses
MyInnerClass mic = new MyInnerClass() {
void Hello() {
System.out.println("Hello from AnonymousTest.Hello!");
}
}; // <-- SEMICOLON IS REQUIRED! It's the end of a
// variable declaration.
mic.Hello();
}
public <T extends Comparable> Comparator<T> getReverseComparator() {
// Test anonymous classes that implement an interface -
// return a Comparator that reverses a list.
Comparator<T> c = new Comparator<T>() {
public int compare(T o1, T o2) {
return o2.compareTo(o1);
}
};
return c;
}
public void TestArgumentInnerClass(MyClass.MyInnerClass mic,
boolean isDone) {
System.out.println("Successfully received the class.");
mic.Hello();
}
public static class MyStaticClass {
void Go() {
System.out.println("Hello from MyClass.MyStaticClass.Go");
}
static void StaticGo() {
System.out.println("Hello from MyClass.MyStaticClass.StaticGo");
}
}
}
/*
Output is as follows:
Hello from MyInnerClass.Hello
Hello from MyInnerClass.Hello
Right.
[a, b, c]
[c, b, a]
Successfully received the class.
Hello from the inner class passed to the argument!
Hello from MyClass.MyStaticClass.Go
Hello from MyClass.MyStaticClass.StaticGo
*/
|