Inner classes and upcasting
So far, inner classes dont seem that dramatic. After all, if its hiding youre after, Java already has a perfectly good hiding mechanismjust give the class package access (visible only within a package) rather than creating it as an inner class.
However, inner classes really come into their own when you start upcasting to a base class, and in particular to an interface. (The effect of producing an interface reference from an object that implements it is essentially the same as upcasting to a base class.) Thats because the inner classthe implementation of the interfacecan then be completely unseen and unavailable to anyone, which is convenient for hiding the implementation. All you get back is a reference to the base class or the interface.
First, the common interfaces will be defined in their own files so they can be used in all the examples:
//: c08:Destination.java
public interface Destination {
String readLabel();
} ///:~
//: c08:Contents.java
public interface Contents {
int value();
} ///:~
Now Contents and Destination represent interfaces available to the client programmer. (The interface, remember, automatically makes all of its members public.)
When you get back a reference to the base class or the interface, its possible that you cant even find out the exact type, as shown here:
//: c08:TestParcel.java
// Returning a reference to an inner class.
class Parcel3 {
private class PContents implements Contents {
private int i = 11;
public int value() { return i; }
}
protected class PDestination implements Destination {
private String label;
private PDestination(String whereTo) {
label = whereTo;
}
public String readLabel() { return label; }
}
public Destination dest(String s) {
return new PDestination(s);
}
public Contents cont() {
return new PContents();
}
}
public class TestParcel {
public static void main(String[] args) {
Parcel3 p = new Parcel3();
Contents c = p.cont();
Destination d = p.dest("Tanzania");
// Illegal -- can't access private class:
//! Parcel3.PContents pc = p.new PContents();
}
} ///:~
In the example, main( ) must be in a separate class in order to demonstrate the privateness of the inner class PContents.
In Parcel3, something new has been added: The inner class PContents is private, so no one but Parcel3 can access it. PDestination is protected, so no one but Parcel3, classes in the same package (since protected also gives package access), and the inheritors of Parcel3 can access PDestination. This means that the client programmer has restricted knowledge and access to these members. In fact, you cant even downcast to a private inner class (or a protected inner class unless youre an inheritor), because you cant access the name, as you can see in class TestParcel. Thus, the private inner class provides a way for the class designer to completely prevent any type-coding dependencies and to completely hide details about implementation. In addition, extension of an interface is useless from the client programmers perspective since the client programmer cannot access any additional methods that arent part of the public interface. This also provides an opportunity for the Java compiler to generate more efficient code.
Normal (non-inner) classes cannot be made private or protected; they may only be given public or package access.