JAVA利用接口實(shí)現(xiàn)多繼承問題的代碼實(shí)操演示
hello,上文帶大家學(xué)習(xí)了java中類的繼承,我們可以創(chuàng)建一個父類,將類中的共性抽取出來,通過子類繼承的方式來實(shí)現(xiàn)代碼的復(fù)用。今天帶大家學(xué)習(xí)不同類之間的另外幾種關(guān)系,即多態(tài)抽象類和接口。
多態(tài)的概念
多態(tài),從字面意思去形象的理解可以解釋為:針對不同的對象執(zhí)行某一行為時(shí),不同的對象會有不同的狀態(tài)。
比如貓和狗都是動物,他們都有進(jìn)食這個行為但是當(dāng)我們調(diào)用狗這個對象時(shí),吃的是狗糧,而調(diào)用貓時(shí),則會選擇吃貓食。
代碼實(shí)操演示
class Animal{ String name; int age; public Animal(String name,int age){ this.name=name; this.age=age; } public void eat(){ System.out.println("正在吃飯"); } } class Cat extends Animal{ public Cat(String name, int age) { super(name, age);//調(diào)用父類的構(gòu)造方法 } @Override public void eat() { System.out.println(this.name+"正在吃貓食");; } } class Dog extends Animal{ public Dog(String name, int age) { super(name, age); } @Override public void eat() { System.out.println(this.name+"正在吃狗糧"); } } public class Test { public static void eat(Animal a){ a.eat();//這里放的是父類具體引用的是誰看傳的對象 } public static void main(String[] args) { Cat cat=new Cat("寶寶",3); Dog dog=new Dog("旺財(cái)",3); eat(dog);//傳的狗 eat(cat);//傳的貓,這里其實(shí)就是動態(tài)綁定 } }
這里還是解釋一下,我們通過子類方法對父類的重寫,后面又在Test類里創(chuàng)建eat()這里傳的是Animal類,由于Animal是Dog和Cat的父類,所以后面我們在調(diào)用eat()時(shí)可以傳Dog和Cat形,即小范圍包含于大范圍。這就是多態(tài)的含義。
類中方法的重寫:
重寫:又稱覆蓋,子類可以對父類中的非靜態(tài),非private,非final,非構(gòu)造方法的其他方法進(jìn)行重新定義,注意:重寫的方法返回值不能改變,方法的參數(shù)不能改變,方法名也不能改變。即方法的外殼,不變只對里面進(jìn)行重新編寫。我們可以根據(jù)子類的需要對父類中的方法進(jìn)行重新定義。通常重寫的方法會有一個標(biāo)簽 @override,上面的程序里有提及。
這里可以對比記憶一下我們學(xué)過的重載:
注意:重寫是對于子類和父類中研究的,即不同類之間,而重載是在一個類中實(shí)現(xiàn)了多個參數(shù)不同的同名的方法。
動態(tài)綁定:即不能立馬確定方法的行為,編譯時(shí)不能確定,等到運(yùn)行時(shí)才能世道方法到底調(diào)用的是哪個方法的類。
父類當(dāng)中的向下轉(zhuǎn)移和向上轉(zhuǎn)移
就是將子類引用給父類來使用,將小范圍賦值給大范圍,但本質(zhì)上仍然為子類對象。
所以運(yùn)行的結(jié)果為寶寶吃貓食。
當(dāng)然你也可以使用Dog類來進(jìn)行向下轉(zhuǎn)型,因?yàn)锳nimal也包含Dog。
直接賦值
方法的返回值
方法的參數(shù)
直接賦值:
Animal animal=new Cat("寶寶",10);
當(dāng)做返回值:
向上轉(zhuǎn)型的優(yōu)點(diǎn):代碼更加靈活。
向上轉(zhuǎn)型的缺點(diǎn):無法調(diào)用子類中的特有方法。
那如果我們就是要調(diào)用子類中的特有方法怎么辦呢?這就需要使用向下轉(zhuǎn)型了。
向下轉(zhuǎn)型:
我們可以使用關(guān)鍵字instanceof來對向下轉(zhuǎn)型的對象做一層檢驗(yàn),保障了代碼的安全性。
if(animal instanceof Cat){ cat=(Cat)animal; cat.mew();
這里只有animal引用了Cat類的對象才執(zhí)行if語句。
多態(tài)的優(yōu)點(diǎn)
那么多態(tài)到底有什么優(yōu)點(diǎn)呢,這里給大家總結(jié)一下,多態(tài)可以降低代碼的圈復(fù)雜度,可以避免使用過多的if-else語句,其次,可拓展能力強(qiáng)需要新增一個類時(shí),直接繼承就好,需要注意構(gòu)造方法么有多態(tài)性。
class B { public B() { // do nothing func(); } public void func() { System.out.println("B.func()"); } } class D extends B { private int num = 1; @Override public void func() { System.out.println("D.func() " + num); } } public class Test { public static void main(String[] args) { D d = new D(); } } // 執(zhí)行結(jié)果 D.func() 0
這里給大家一段有意思的代碼,運(yùn)行結(jié)果你猜對了嗎,原因是new() D之后,第一步應(yīng)該是調(diào)用父類的構(gòu)造方法,即func(),但是構(gòu)造方法在子類中被重寫,所以調(diào)用的是子類中的func(),此時(shí)子類中的成員變量還沒有賦值所以num仍然為0,所以運(yùn)行結(jié)果為D.func() 0
抽象類即抽象方法的重寫
其實(shí),我們在最上面的代碼中發(fā)現(xiàn)了一個問題,很多類由于不能將一個事物準(zhǔn)確描述出來,針對不同的事物的行為不同,執(zhí)行的方法也應(yīng)該不同,比如Animal中的eat()并不能準(zhǔn)確描述狗吃的狗糧,貓吃的貓糧,我們在狗類和貓類中還是要重寫這個eat()方法,類似與Animal的這些類可以理解為抽象類。
抽象類,修飾限定符為public abstract,抽象類中的抽象方法(修飾符也是public abstract)類似與eat(),是不能有具體的定義的,原因很好理解,即使你寫了,每個子類還得重寫這個方法,我們只聲明這個方法即可。注意:有抽象方法的類一定是抽象類,抽象類不一定含有抽象方法,抽象類也是類可以定義普通的成員變量,方法甚至是構(gòu)造方法。(非常重要!?。?!)
上代碼理解一下:
//抽象類 public Abstract Animal{ public abstract void eat();//抽象方法 public abstract void look();//抽象方法 }
抽象類也不能實(shí)例化對象,因?yàn)槌橄耦悷o法完整描述一個事物,他只能被子類繼承,然后子類必須將抽象類當(dāng)中的抽象方法進(jìn)行重寫,否則編譯報(bào)錯,
抽象方法不能是 private 的,因?yàn)樽宇愡€要重寫抽象方法的。
抽象方法不能被final和static修飾,因?yàn)槌橄蠓椒ㄒ蛔宇愔貙?/strong> 。
接口的概念:
說到接口,我們第一想到的應(yīng)該是USB接口插座...,這些當(dāng)然都算接口,那么讓我來說接口的特性的話,我覺得接口首先是一個封裝好了的東西,并且它有著自己的功能,如果某個東西有了接口,那么他也應(yīng)該具有接口的特性。
在java中接口是多個類的公共規(guī)范,是一種引用數(shù)據(jù)類型,接口的定義格式與定義類的格式基本相同,將class關(guān)鍵字換成 interface 關(guān)鍵字,就定義了一個接口。
interface A{ public abstract void method1(); // public abstract 是固定搭配,可以不寫 public void method2(); abstract void method3() }
接口不能直接使用,必須要有一個"實(shí)現(xiàn)類"來"實(shí)現(xiàn)"該接口,實(shí)現(xiàn)接口中的所有抽象方法。 這也比較好理解,畢竟接口只是實(shí)現(xiàn) 了某個特定的功能,并不能描述一個具體的對象。我們使用關(guān)鍵字implement將類和接口連接起來。
public class Animal implements IRunning{ // ... }
這里給大家舉一個電腦的例子:
// USB接口 public interface USB { void openDevice(); void closeDevice(); }
// 鼠標(biāo)類,實(shí)現(xiàn)USB接口 public class Mouse implements USB { @Override public void openDevice() { System.out.println("打開鼠標(biāo)"); } @Override public void closeDevice() { System.out.println("關(guān)閉鼠標(biāo)"); } public void click(){ System.out.println("鼠標(biāo)點(diǎn)擊"); } }
// 鍵盤類,實(shí)現(xiàn)USB接口 public class KeyBoard implements USB { @Override public void openDevice() { System.out.println("打開鍵盤"); } @Override public void closeDevice() { System.out.println("關(guān)閉鍵盤"); } public void inPut(){ System.out.println("鍵盤輸入"); } }
// 筆記本類:使用USB設(shè)備 public class Computer { public void powerOn(){ System.out.println("打開筆記本電腦"); } public void powerOff(){ System.out.println("關(guān)閉筆記本電腦"); }
public void useDevice(USB usb){ usb.openDevice(); if(usb instanceof Mouse){ Mouse mouse = (Mouse)usb; mouse.click(); }else if(usb instanceof KeyBoard){ KeyBoard keyBoard = (KeyBoard)usb; keyBoard.inPut(); } usb.closeDevice(); } }
// 測試類: public class TestUSB { public static void main(String[] args) { Computer computer = new Computer(); computer.powerOn(); // 使用鼠標(biāo)設(shè)備 computer.useDevice(new Mouse()); // 使用鍵盤設(shè)備 computer.useDevice(new KeyBoard()); computer.powerOff(); } }
接口雖然是一種引用類型但是,他不能new(),必需通過引用類來重寫接口中的所有方法,并且每個方法都默認(rèn)為public abstract,也可以使用static和default修飾但是必須立即定義該方法,注意重寫方法時(shí)一定要用public修飾。
public interface USB { void openDevice(); // 默認(rèn)是public的 void closeDevice(); // 默認(rèn)是public的 } public class Mouse implements USB { @Override void openDevice() { System.out.println("打開鼠標(biāo)"); } // ... } // 編譯報(bào)錯,重寫USB中openDevice方法時(shí),不能使用默認(rèn)修飾符 // 正在嘗試分配更低的訪問權(quán)限; 以前為public
而且一個類是可以實(shí)現(xiàn)多個接口的,這也間接解決了java的多繼承問題。
class Animal { protected String name; public Animal(String name) { this.name = name; } }
interface IFlying { void fly(); } interface IRunning { void run(); } interface ISwimming { void swim(); }
class Cat extends Animal implements IRunning { public Cat(String name) { super(name); } @Override public void run() { System.out.println(this.name + "正在用四條腿跑"); } }
class Fish extends Animal implements ISwimming { public Fish(String name) { super(name); } @Override public void swim() { System.out.println(this.name + "正在用尾巴游泳"); } }
總結(jié)
到此這篇關(guān)于JAVA利用接口實(shí)現(xiàn)多繼承問題的文章就介紹到這了,更多相關(guān)JAVA用接口實(shí)現(xiàn)多繼承內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中Collection、List、Set、Map之間的關(guān)系總結(jié)
今天小編就為大家分享一篇關(guān)于Java中Collection、List、Set、Map之間的關(guān)系總結(jié),小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-02-02SpringBoot URL帶有特殊字符([]/{}等),報(bào)400錯誤的解決
這篇文章主要介紹了SpringBoot URL帶有特殊字符([]/{}等),報(bào)400錯誤的解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02SpringBoot自定義MessageConverter與內(nèi)容協(xié)商管理器contentNegotiationManag
這篇文章主要介紹了SpringBoot自定義MessageConverter與內(nèi)容協(xié)商管理器contentNegotiationManager的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-10-10詳解如何實(shí)現(xiàn)SpringBoot的底層注解
今天給大家?guī)淼奈恼率侨绾螌?shí)現(xiàn)SpringBoot的底層注解,文中有非常詳細(xì)的介紹及代碼示例,對正在學(xué)習(xí)java的小伙伴很有幫助,需要的朋友可以參考下2021-06-06詳解關(guān)于mybatis-plus中Service和Mapper的分析
這篇文章主要介紹了詳解關(guān)于mybatis-plus中Service和Mapper的分析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09