Inner classes
in methods and scopes
What you’ve seen so far encompasses the typical use for inner classes. In general, the code that you’ll write and read involving inner classes will be “plain” inner classes that are simple and easy to understand. However, the design for inner classes is quite complete, and there are a number of other, more obscure, ways that you can use them if you choose; inner classes can be created within a method or even an arbitrary scope. There are two reasons for doing this:
- As shown previously, you’re implementing an interface of some kind so
that you can create and return a reference.
- You’re solving a complicated problem and you want to create a class to
aid in your solution, but you don’t want it publicly available.
A class
defined within a method
- A class defined within a scope inside a method
- An anonymous class implementing an interface
- An anonymous class extending a class that has a nondefault constructor
- An anonymous class that performs field initialization
- An anonymous class that performs construction using instance initialization
(anonymous inner classes cannot have
constructors)
Although it’s an ordinary class with an implementation, Wrapping is also being used as a common “interface” to its derived classes:
//: c08:Wrapping.java
public class Wrapping {
private int i;
public Wrapping(int x) { i = x; }
public int value() { return i; }
} ///:~
You’ll notice that Wrapping has a constructor that requires an argument, to make things a bit more interesting.
The first example shows the creation of an entire class within the scope of a method (instead of the scope of another class). This is called a local inner class:
//: c08:Parcel4.java
// Nesting a class within a method.
public class Parcel4 {
public Destination dest(String s) {
class PDestination implements Destination {
private String label;
private PDestination(String whereTo) {
label = whereTo;
}
public String readLabel() { return label; }
}
return new PDestination(s);
}
public static void main(String[] args) {
Parcel4 p = new Parcel4();
Destination d = p.dest("Tanzania");
}
} ///:~
The class PDestination is part of dest( ) rather than being part of Parcel4. (Also notice that you could use the class identifier PDestination for an inner class inside each class in the same subdirectory without a name clash.) Therefore, PDestination cannot be accessed outside of dest( ). Notice the upcasting that occurs in the return statement—nothing comes out of dest( ) except a reference to Destination, the base class. Of course, the fact that the name of the class PDestination is placed inside dest( ) doesn’t mean that PDestination is not a valid object once dest( ) returns.
The next example shows how you can nest an inner class within any arbitrary scope:
//: c08:Parcel5.java
// Nesting a class within a scope.
public class Parcel5 {
private void internalTracking(boolean b) {
if(b) {
class TrackingSlip {
private String id;
TrackingSlip(String s) {
id = s;
}
String getSlip() { return id; }
}
TrackingSlip ts = new TrackingSlip("slip");
String s = ts.getSlip();
}
// Can't use it here! Out of scope:
//! TrackingSlip ts = new TrackingSlip("x");
}
public void track() { internalTracking(true); }
public static void main(String[] args) {
Parcel5 p = new Parcel5();
p.track();
}
} ///:~
The class TrackingSlip is nested inside the scope of an if statement. This does not mean that the class is conditionally created—it gets compiled along with everything else. However, it’s not available outside the scope in which it is defined. Other than that, it looks just like an ordinary class.