迄今為止,內部類看起來仍然沒什麼特別的地方。畢竟,用它實現隱藏顯得有些大題小做。Java已經有一個非常優秀的隱藏機制——只允許類成為“友好的”(只在一個包內可見),而不是把它創建成一個內部類。
然而,當我們准備上溯造型到一個基礎類(特別是到一個接口)的時候,內部類就開始發揮其關鍵作用(從用於實現的對象生成一個接口句柄具有與上溯造型至一個基礎類相同的效果)。這是由於內部類隨後可完全進入不可見或不可用狀態——對任何人都將如此。所以我們可以非常方便地隱藏實施細節。我們得到的全部回報就是一個基礎類或者接口的句柄,而且甚至有可能不知道准確的類型。就象下面這樣:
//: Parcel3.java
// Returning a handle to an inner class
package c07.parcel3;
abstract class Contents {
abstract public int value();
}
interface Destination {
String readLabel();
}
public class Parcel3 {
private class PContents extends 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();
}
}
class Test {
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 c = p.new PContents();
}
} ///:~
現在,Contents和Destination代表可由客戶程序員使用的接口(記住接口會將自己的所有成員都變成public屬性)。為方便起見,它們置於單獨一個文件裡,但原始的Contents和Destination在它們自己的文件中是相互public的。
在Parcel3中,一些新東西已經加入:內部類PContents被設為private,所以除了Parcel3之外,其他任何東西都不能訪問它。PDestination被設為protected,所以除了Parcel3,Parcel3包內的類(因為protected也為包賦予了訪問權;也就是說,protected也是“友好的”),以及Parcel3的繼承者之外,其他任何東西都不能訪問PDestination。這意味著客戶程序員對這些成員的認識與訪問將會受到限制。事實上,我們甚至不能下溯造型到一個private內部類(或者一個protected內部類,除非自己本身便是一個繼承者),因為我們不能訪問名字,就象在classTest裡看到的那樣。所以,利用private內部類,類設計人員可完全禁止其他人依賴類型編碼,並可將具體的實施細節完全隱藏起來。除此以外,從客戶程序員的角度來看,一個接口的范圍沒有意義的,因為他們不能訪問不屬於公共接口類的任何額外方法。這樣一來,Java編譯器也有機會生成效率更高的代碼。
普通(非內部)類不可設為private或protected——只允許public或者“友好的”。
注意Contents不必成為一個抽象類。在這兒也可以使用一個普通類,但這種設計最典型的起點依然是一個“接口”。