Home > Java 1.6 Tutorial > Inner classes

Inner classes


We moved. Please visit this link for this post.

 

 

 

Intro
An Inner class (aka Nested class) is a class declared entirely within the body of another class or interface.
The inner class is a valuable feature because it allows you to group classes that logically belong together and to control the visibility of one within the other. However, it’s important to understand that inner classes are distinctly different from composition. At first, inner classes look like a simple code-hiding mechanism: You place classes inside other classes. Initially, inner classes may seem odd, and it will take some time to become comfortable using them in your designs.

Creating an inner class
// OuterClass.java

public class OuterClass {
private int x = 7;
// inner class definition
class InnerClass {
public void showOuter() {
System.out.println("OuterClass x is " + x);
}
} // close inner class definition
} // close outer class

Notice that the inner class is indeed accessing a private member of the outer class. That’s fine, because the inner class is also a member of the outer class. So just as any member of the outer class can access any other member of the outer class, private or not, the inner class—also a member—can do the same. Now we know how to write the code giving an inner class access to members of the outer class.

Instantiating an Inner Class
To create an instance of an inner class, you must have an instance of the outer class to tie to the inner class. There are no exceptions to this rule: an inner class instance can never stand alone without a direct relationship to an instance of the outer class.

Instantiating an Inner Class from Within the Outer Class
Very often, it is the outer class that creates instances of the inner class, since it is usually the outer class wanting to use the inner instance as a helper for its own personal use. We’ll modify the OuterClass class to create an instance of InnerClass.
// OuterInst.java

class OuterInst {
private int x = 7;
public void makeInner() {
Inner in = new Inner(); // make an inner instance
in.seeOuter();
}
class Inner {
public void seeOuter() {
System.out.println("OuterInst x is " + x);
}
}
}

Creating an Inner Class Object from Outside the Outer Class Instance Code
//OuterClass.java

public static void main(String[] args) {
OuterClass.InnerClass inner = new OuterClass().new InnerClass(); // gotta get an instance!
inner.showOuter();
}

Referencing the Inner or Outer Instance from Within the Inner Class
How does an object refer to itself normally? By using the this reference. Here is a quick review of this:
The keyword this can be used only from within instance code. In other words, not within static code.
The this reference is a reference to the currently executing object. In other words, the object whose reference was used to invoke the currently running method. The this reference is the way an object can pass a reference to itself to some other code, as a method argument:

public void myMethod() {
MyClass mc = new MyClass();
mc.doStuff(this); // pass a ref to object running myMethod
}

Full example:
//Outer.java

class Outer {
private int x = 7;
public void makeInner() {
Inner in = new Inner();
in.seeOuter();
}
class Inner {
public void seeOuter() {
System.out.println("Outer x is " + x);
System.out.println("Inner class ref is " + this);
System.out.println("Outer class ref is " + Outer.this);
}
}
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner();
inner.seeOuter();
}
}

So the rules for an inner class referencing itself or the outer instance are as follows:
To reference the inner class instance itself, from within the inner class code, use this.
To reference the “outer this” (the outer class instance) from within the inner class code, use NameOfOuterClass.this (example, Outer.this).

Member Modifiers Applied to Inner Classes
A regular inner class is a member of the outer class just as instance variables and methods are, so the following modifiers can be applied to an inner class:
• final
• abstract
• public
• private
• protected
• static—but static turns it into a static nested class not an inner class
• strictfp

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:

class Outer2 {
private String x = "Outer2";
void doStuff() {
class MyInner {
public void seeOuter() {
System.out.println("Outer x is " + x);
} // close inner class method
} // close inner class definition
} // close outer class method doStuff()
} // close outer class

The preceding code declares a class, MyOuter2, with one method, doStuff(). But inside doStuff(), another class, MyInner, is declared, and it has a method of its own, seeOuter(). The code above is completely useless, however, because it never instantiates the inner class! Just because you declared the class doesn’t mean you created an instance of it. So to use the inner class you must make an instance of it somewhere within the method but below the inner class definition (or the compiler won’t be able to find the inner class). The following legal code shows how to instantiate and use a method-local inner class:
//Outer2.java

class Outer2 {
private String x = "Outer2";
void doStuff() {
class Inner {
public void seeOuter() {
System.out.println("Outer x is " + x);
} // close inner class method
} // close inner class definition
Inner mi = new Inner(); // This line must come
// after the class
mi.seeOuter();
} // close outer class method doStuff()
} // close outer class

What a Method-Local Inner Object Can and Can’t Do
A method-local inner class can be instantiated only within the method where the inner class is defined. In other words, no other code running in any other method—inside or outside the outer class—cans 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. 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 blown away and the variable is history. 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.

//Outer2_1.java

class Outer2_1 {
private String x = "Outer2";
void doStuff() {
String z = "local variable";
class MyInner {
public void seeOuter() {
System.out.println("Outer x is " + x);
System.out.println("Local variable z is " + z); // Won't Compile!
} // close inner class method
} // close inner class definition
} // close outer class method doStuff()
} // close outer class

Compiling the preceding code really upsets the compiler:
MyOuter2.java: 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”; // Now inner object can use it

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.

Anonymous Inner Classes
We are going to look at the most unusual syntax you might ever see in Java; inner classes declared without any class name at all (hence the word anonymous). And if that’s not weird enough, you can define these classes not just within a method, but even within an argument to a method.
//Food.java

class Popcorn {
public void pop() {
System.out.println("popcorn");
}
}
public class Food {
Popcorn p = new Popcorn() {
public void pop() {
System.out.println("anonymous popcorn");
}
};
}

Let’s look at what’s in the preceding code:
We define two classes, Popcorn and Food.
Popcorn has one method, pop().
Food has one instance variable, declared as type Popcorn. That’s it for Food. Food has no methods.
Polymorphism is in play when anonymous inner classes are involved. Remember that, as in the preceding Popcorn 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!

Very often anonymous class used as implementer of the specified interface type.
Example:
//Food2.java

interface Cookable {
public void cook();
}

class Food2 {
Cookable c = new Cookable() {
public void cook() {
System.out.println("anonymous cookable implementer");
}
};
}

The preceding code, like the Popcorn example, still creates an instance of an anonymous inner class, but this time the new just-in-time class is an implementer of the Cookable interface. And note that this is the only time you will ever see the syntax
new Cookable()
where Cookable 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 Cookable object, it’s creating an instance of a new, anonymous, implementer of Cookable. You can read this line:
Cookable c = new Cookable() {}
as, “Declare a reference variable of type Cookable that, obviously, will refer to an object from a class that implements the Cookable interface. But, oh yes, we don’t yet have a class that implements Cookable, 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 Cookable, 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
Example:
//WonderfulClass.java

class WonderfulClass {
void go() {
Bar b = new Bar();
b.doStuff(new Foo() {
public void foof() {
System.out.println("foofy");
} // end foof method
}); // end inner class def, arg, and b.doStuff stmt.
} // end go()
} // end class

interface Foo {
void foof();
}

class Bar {
void doStuff(Foo f) {
}
}

All the action starts when we are calling doStuff() on a Bar object, but the method takes an instance that IS-A Foo, where Foo is an interface. So we must make both an implementation class and an instance of that class, all right here in the argument to doStuff(). So that’s what we do. We write
new Foo() {
to start the new class definition for the anonymous class that implements the Foo interface. Foo has a single method to implement, foof(), so we implement the foof() method.
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.
If they’re argument local, they end like this:
});
but if they’re just plain-old anonymous classes, then they end like this:
};

Static Nested Classes
A static nested class is simply a class that’s a static member of the enclosing class:

class BigOuter {
static class Nested {
}
}

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 nested 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 Nested Classes
You use standard syntax to access a static nested class from its enclosing class. The syntax for instantiating a static nested class from a non-enclosing class is a little different from a normal inner class, and looks like this:
//Broom.java

class BigOuter {
static class Nest {
void go() {
System.out.println("hi");
}
}
}

class Broom {
static class B2 {
void goB2() {
System.out.println("hi 2");
}
}

public static void main(String[] args) {
BigOuter.Nest n = new BigOuter.Nest(); // both class names
n.go();
B2 b2 = new B2(); // access the enclosed class
b2.goB2();
}
}

Is it useful information for you?

Advertisements
Categories: Java 1.6 Tutorial
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: