Java中的多重继承与组合vs继承
有時(shí)我寫了幾篇有關(guān)Java 繼承 , 接口和組成的文章。 在這篇文章中,我們將研究多重繼承,然后學(xué)習(xí)組成優(yōu)于繼承的好處。
Java中的多重繼承
多重繼承是創(chuàng)建具有多個(gè)超類的單個(gè)類的能力。 與其他一些流行的面向?qū)ο蟮木幊陶Z言(例如C ++)不同, java不提供對類中多重繼承的支持 。 Java不支持類中的多重繼承,因?yàn)樗赡軐?dǎo)致菱形問題 ,而不是提供解決復(fù)雜問題的方法,還有更好的方法來實(shí)現(xiàn)與多重繼承相同的結(jié)果。
鉆石問題
為了輕松理解鉆石問題,我們假設(shè)Java支持多重繼承。 在這種情況下,我們可以像下面的圖像那樣有一個(gè)類層次結(jié)構(gòu)。
假設(shè)SuperClass是一個(gè)抽象類,聲明了一些方法,而ClassA,ClassB是具體類。
超類.java
package com.journaldev.inheritance;public abstract class SuperClass {public abstract void doSomething(); }ClassA.java
package com.journaldev.inheritance;public class ClassA extends SuperClass{@Overridepublic void doSomething(){System.out.println("doSomething implementation of A");}//ClassA own methodpublic void methodA(){} }ClassB.java
package com.journaldev.inheritance;public class ClassB extends SuperClass{@Overridepublic void doSomething(){System.out.println("doSomething implementation of B");}//ClassB specific methodpublic void methodB(){} }現(xiàn)在,讓我們說ClassC的實(shí)現(xiàn)如下所示,它擴(kuò)展了ClassA和ClassB。
ClassC.java
package com.journaldev.inheritance;public class ClassC extends ClassA, ClassB{public void test(){//calling super class methoddoSomething();}}注意, test()方法正在調(diào)用超類doSomething()方法,這導(dǎo)致歧義,因?yàn)榫幾g器不知道要執(zhí)行哪個(gè)超類方法,并且由于菱形類圖,它被稱為Diamond Problem,這是Java不支持類中的多重繼承的主要原因。
請注意,上述具有多類繼承的問題也可能只出現(xiàn)在三個(gè)類中,它們?nèi)烤哂兄辽僖粋€(gè)通用方法。
接口中的多重繼承
您可能已經(jīng)注意到,我一直在說類不支持多重繼承,但接口支持多重繼承,并且單個(gè)接口可以擴(kuò)展多個(gè)接口,下面是一個(gè)簡單的示例。
接口A.java
package com.journaldev.inheritance;public interface InterfaceA {public void doSomething(); }接口B.java
package com.journaldev.inheritance;public interface InterfaceB {public void doSomething(); }注意,兩個(gè)接口都聲明了相同的方法,現(xiàn)在我們可以有一個(gè)擴(kuò)展這兩個(gè)接口的接口,如下所示。
接口C.java
package com.journaldev.inheritance;public interface InterfaceC extends InterfaceA, InterfaceB {//same method is declared in InterfaceA and InterfaceB bothpublic void doSomething();}這樣做非常好,因?yàn)榻涌趦H聲明方法,并且實(shí)際實(shí)現(xiàn)將由實(shí)現(xiàn)接口的具體類來完成,因此在接口的多重繼承中不存在任何歧義的可能性。
這就是為什么Java類可以實(shí)現(xiàn)多重繼承的原因,例如下面的示例。
接口Impl.java
package com.journaldev.inheritance;public class InterfacesImpl implements InterfaceA, InterfaceB, InterfaceC {@Overridepublic void doSomething() {System.out.println("doSomething implementation of concrete class");}public static void main(String[] args) {InterfaceA objA = new InterfacesImpl();InterfaceB objB = new InterfacesImpl();InterfaceC objC = new InterfacesImpl();//all the method calls below are going to same concrete implementationobjA.doSomething();objB.doSomething();objC.doSomething();}}您是否注意到,每當(dāng)我覆蓋任何超類方法或?qū)崿F(xiàn)任何接口方法時(shí),我都使用@Override注釋,它是三個(gè)內(nèi)置的Java注釋之一,并且在覆蓋任何方法時(shí)都應(yīng)始終使用覆蓋注釋 。
救援人員組成
因此,如果我們想在ClassC利用ClassA函數(shù)methodA()和ClassB函數(shù)methodB() ,該解決方案在于使用composition ,這是ClassC的重構(gòu)版本,該版本使用了composition來同時(shí)利用類方法和doSomething ()方法來自其中一個(gè)對象。
ClassC.java
package com.journaldev.inheritance;public class ClassC{ClassA objA = new ClassA();ClassB objB = new ClassB();public void test(){objA.doSomething();}public void methodA(){objA.methodA();}public void methodB(){objB.methodB();} }組合與繼承
Java編程的最佳實(shí)踐之一是“通過接口支持組合”,我們將研究一些偏愛這種方法的方面。
ClassC.java
package com.journaldev.inheritance;public class ClassC{public void methodC(){} }ClassD.java
package com.journaldev.inheritance;public class ClassD extends ClassC{public int test(){return 0;} }上面的代碼可以編譯并正常工作,但是如果ClassC實(shí)現(xiàn)更改如下,該怎么辦:
ClassC.java
package com.journaldev.inheritance;public class ClassC{public void methodC(){}public void test(){} }請注意,子類中已經(jīng)存在test()方法,但是返回類型有所不同,現(xiàn)在ClassD將無法編譯,并且如果您使用的是任何IDE,它將建議您更改超類或子類中的返回類型。
現(xiàn)在想象一下這樣的情況:我們具有多個(gè)級(jí)別的類繼承,并且超類不受我們控制,我們別無選擇,只能更改子類方法簽名或名稱以消除編譯錯(cuò)誤,我們還必須在所有方面進(jìn)行更改子類方法被調(diào)用的地方,因此繼承使我們的代碼易碎。
組合永遠(yuǎn)不會(huì)發(fā)生上述問題,這使其比繼承更有利。
組合可以幫助我們提供對超類方法的受控訪問,而繼承不提供對超類方法的任何控制,這也是組合優(yōu)于繼承的主要優(yōu)勢之一。
ClassC.java
package com.journaldev.inheritance;public class ClassC{SuperClass obj = null;public ClassC(SuperClass o){this.obj = o;}public void test(){obj.doSomething();}public static void main(String args[]){ClassC obj1 = new ClassC(new ClassA());ClassC obj2 = new ClassC(new ClassB());obj1.test();obj2.test();} }上面程序的輸出是:
doSomething implementation of A doSomething implementation of B這種方法調(diào)用的靈活性在繼承中不可用,從而提倡了最佳做法,即在繼承方面偏向于組合。
理想情況下,只有在所有情況下父類和子類的“ is-a ”關(guān)系均成立時(shí)才應(yīng)使用繼承,否則我們應(yīng)該繼續(xù)進(jìn)行組合。
翻譯自: https://www.javacodegeeks.com/2013/08/multiple-inheritance-in-java-and-composition-vs-inheritance.html
總結(jié)
以上是生活随笔為你收集整理的Java中的多重继承与组合vs继承的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何查看自己或者别人电脑里的隐藏文件电脑
- 下一篇: 如何使用Java 5 Executor框