Java 為什么不支持super多級調用,即super.super ?
一、幾種解釋
1. 對於子類而言,已經繼承了父類的所有,那么自然也繼承了爺爺類的所有,使用super.super 屬於多此一舉。
2. super.super 屬於多繼承錯誤。
3. super是當前類的私有成員(或者說成是“隱含”的私有成員),代表着父類;而super.super的意思是要訪問父類中的私有成員,所以不可能。或者換種說法,super和this其實都不是類的成員,根本不存在 對象.成員 (即類似於:this.super,super.this)的語句。
4. super.super 從理論上是可行的。
先從this說起,所有intance的方法在編譯時都會被編譯器多加入一個參數,就是this,這個this相當於一個指向當前對象本身的指針。運行時通過這個this,虛擬機就能找到當前對象在內存中的地址,從而得知當前對象的確切類型,從而實現多態。
super的作用和this相似,編譯器會把它作為一個參數加入instance的方法里。在虛擬機運行時就會去執行當前對象父類的方法。
那么我們以此類推,super.super其實是完全可以實現的。
Java之所以沒有這種語句,完全是出於軟件工程的考慮。
5. super.super 破壞了Java的封裝性,對於子類而言,它只考慮它自己和父類,而不關心父類的父類
二、本人思考
首先來解決我們是否會需要super.super的問題,也就是它是否多此一舉,即解釋1。
答案是否定的。
我們假設下面一種簡單情況。
圖形 --> 長方形 --> 正方形
為表示基本信息
圖形 toString返回:中心點(x,y),顏色(R,G, B), 壓縮比, 偏移,...
長方形 toString返回:super.toString() , 長, 寬
那現在正方形怎樣的toString()更合適顯示出它的基本信息呢?自然應該是:圖形.toString() ,邊長。而非長方形.toString。
這里的圖形.toString 在正方形類中正是super.super.toString()
總結起來就是說: 假設爺爺有方法A1,父親繼承爺爺有了A1,但是重寫成A2;之后兒子繼承了父親,擁有是A2,而並非A1。所以我們還是有可能需要用到祖父級的方法的。
那么super.super是否屬於多繼承錯誤呢?
我們知道禁止多繼承主要是為了防止沖突。但是我不認為在這里是合理解釋,因為首先在建立類的時候,就決定了任何方法的標識都唯一指向一個方法:
(1)子類相對於父類新增的方法
(2)子類繼承於父類的方法
(3)子類繼承於父類,但是經過重寫的方法。(父類方法被拋棄)
同時對象調用方法時是以A.method()出現的,並沒有A.super.method(),更不可能有A.super.super.method(),即使有,也已經完全區別開來了。所以不會有沖突產生!
解釋3是說得通的,將this和super都看做一個“隱含”的私有成員(或者只是個標識)。私有性質限制了其他類的訪問,或者"."的標識禁止了對象.對象這樣的語法,也就是JDK規范的問題,this.super,super.this等也不被允許。
如果上述解釋3是根本原因,那自然好過。而super.super歷史上是存在的,http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4209952, 那么語法規范不太可能是根本原因。
權威答案呢?不見得有了。解釋4和5基本上可以統一說成是基於經濟、實用性的考量。
- 回到super多級調用需不需要的問題,子類其實繼承的是父類以上輩分的方法,需要用super多級調用來追溯到更“原始”的方法往往是特殊情況,實用性不強。
- super多級調用使得對象的封裝性受到了威脅。
總的來說就是super多級調用得不償失!這是我最傾向的一個答案!
這是很老的一個問題,希望有人知道更細致、權威的解釋告訴一聲。
三、替代super.super.xxx的方法實現
class A {
public void method() { }
}
class B extends A {
public void method() { }
protected void superMethod() {
super.method();
}
}
class C extends B {
public void method() { }
void test() {
method(); // C.method()
super.method(); // B.method()
superMethod(); // A.method()
}
}
