《Java程式設計思想》之為什麼需要內部類?
13、為什麼需要內部類?
1).內部類最吸引人注意的原因是:每個內部類都能獨立的繼承自一個(介面的)實現,所以無論外圍類是否已經繼承了某個就(介面的)實現,對於內部類都沒有影響。
2).一個類中以某種方式實現兩個介面。由於介面的靈活性,你有兩種選擇:使用單一類,或者使用內部類。從實現觀點看,以下倆種方式沒什麼區別。
interface A{} interface B{} class X implements A, B{} class Y implements A{ B makeB(){ return new B(){ }; } } public class MultiInterfaces{ static void takesA(A a){} static void takesB(B b){} public static void main(String[] args){ X x = new X(); Y y = new Y(); takesA(x); takesA(y); takesB(x); takesB(y.makeB()); } }
3).如果擁有的是抽象類或具體的類,而不是介面,那就只能使用內部類才能實現多重繼承。
4).內部類還可以獲得其他一些特性(不是很理解!!):
·內部類可以有多個例項,每個例項都有自己的狀態資訊,並且與外圍類物件的資訊相互獨立。
·在單個的外圍類中,可以讓多個內部類以不用的方式實現同一介面,或繼承同一個類。
·建立內部類物件的時刻並不依賴外圍類物件的建立。
·內部類並沒有令人迷惑的“is-a”關係;它就是一個獨立的實體。
請看下面例子:
interface Selector{ boolean end(); Object current(); void next(); } public class Sequence{ private Object[] objects; private int next = 0; public Sequence(int size){ objects = new Object[size]; } public void add(Object x){ if(next < objects.length) objects[next++] = x; } private class SSelector implements Selector{ private int i = 0; public boolean end(){ return i == objects.length; } public Object current(){ return objects[i]; } public void next(){ if(i < objects.length) i++; } } public Selector getSelector(){ return new SSelector(); } public static void main(String[] args){ Sequence sequence = new Sequence(10); for(int i = 0; i < 10; i++) sequence.add(Integer.toString(i)); Selector selector = sequence.getSelector(); while(!selector.end()){ System.out.println(selector.current()); selector.next(); } } }
如果Sequence不適用內部類,就必須宣告“Sequence是一個Selector”,對於某個特定的Sequence只能又一個Selector。同時,使用內部類很容易就能擁有另一個方法getRSelector(),用它來生成一個反方向遍歷的Selector。只有內部類才有這種靈活性。
14、閉包是一個可呼叫的物件,它記錄了一些資訊,這些資訊來自於建立它的作用域。內部類是面向物件的閉包。因為它不僅包含外圍類物件(“建立內部類的作用域”)的資訊,還自動擁有一個指向此外圍物件的引用,在此作用域內,內部類操作所有成員,包括“private”成員。
15、Java最具有爭議的問題之一就是,人們認為Java應該包含某種類似指標的機制,以允許回撥。通過回撥
通過內部類提供閉包的功能是完美的解決方案,它比指標更靈活、更安全。見下例:
interface Incrementable{
void increment();
}
//外部類實現介面
class Callee1 implements Incrementable{
private int i = 0;
public void increment(){
i++;
System.out.println(i);
}
}
class MyIncrement{
void increment(){
System.out.println("MyIncrement.increment()");
}
static void func(MyIncrement myIncrement){
myIncrement.increment();
}
}
class Callee2 extends MyIncrement{
private int i = 0;
private void incr(){
i++;
System.out.println(i);
}
//內部類實現介面
public class Closureimplements Incrementable{
public void increment(){
incr();
}
}
Incrementable getCallBackReference(){
return new Closure();//向上轉型
}
}
class Caller{
private Incrementable callBackReference;
Caller(Incrementable callBackReference){
this.callBackReference = callBackReference;
}
void go(){
callBackReference.increment();
}
}
public class Callbacks{
public static void main(String[] args){
Callee1 c1 = new Callee1();
Callee2 c2 = new Callee2();
MyIncrement.func(c2);
Caller caller1 = new Caller(c1);
Caller caller2 = new Caller(c2.getCallBackReference());
caller1.go();
caller1.go();
caller2.go();
caller2.go();
}
}
Callee2繼承自MyIncrement,有一個與Incrementable介面相同名字的increment()方法,但是兩者的Increment()方法行為不同。所以如果Callee2繼承了MyIncrement,就不能為了Incrementable的用途而覆蓋increment()方法,於是只能使用內部類獨立的實現Incrementable。還要注意,當建立了一個內部類時,並沒有在外圍類的介面中新增東西,也沒有修改外圍類的介面。
Callee2中內部類Closure 裡的getCallBackReference()方法,返回一個Incrementable的引用,無論誰獲得此引用,都只能呼叫increment(),除此之外沒有其他功能(不像指標那樣,允許你做很多事情)。
回撥的價值在於它的靈活性——可以在執行時動態決定需要呼叫什麼方法。
16、
1). 應用程式框架(applicationframeword)就是被設計用來解決某類特定問題的一個類或一組類。
2).要執行某個應用程式框架,通常是繼承一個或多個類,並覆蓋某個方法。
3).控制框架是一類特殊的應用程式框架,它用來解決響應事件的需求。
4).主要用來響應事件的系統被稱作事件驅動系統。
以上內容整理自《Java程式設計思想》,若有遺漏,請您不吝指出!