Java中的多態(tài)、抽象類和接口詳解
1.多態(tài)
一個特定類型的變量,可以引用多個不同類型的對象,并且能自動調(diào)用引用對象的方法,也就是根據(jù)引用對象的不同,響應(yīng)不同的操作
方法重寫是多態(tài)的基礎(chǔ),在繼承中,子類擁有和父類相同的方法(方法名稱、參數(shù)、返回值)稱為重寫
package com.itlaobing.demo; public class Pet { public void toHospital() { System.out.println("寵物看病"); } } class Dog extends Pet{ public void toHospital() { System.out.println("狗狗看病"); } } class Cat extends Pet{ public void toHospital() { System.out.println("貓貓看病"); } }
public static void main(String[] args) { Dog dog = new Dog() ; dog.toHospital();//狗狗看病 Cat cat = new Cat(); cat.toHospital(); //貓貓看病 System.out.println("================="); //多態(tài) Pet pet; pet = new Dog(); pet.toHospital();//狗狗看病 pet = new Cat(); pet.toHospital(); //貓貓看病 }
多態(tài)中,變量引用的是哪個對象,就執(zhí)行的是哪個對象中相對應(yīng)的方法。
多態(tài)意味著在一次方法調(diào)用中根據(jù)包含的對象的實際類型(即實際子類的對象)來決定應(yīng)該調(diào)用哪個子類的方法,而不是由用來存儲對象引用變量的類型決定的。當調(diào)用一個方法時,為了實現(xiàn)多態(tài)操作,這個方法即是在父類中聲明過的,也必須是在子類中重寫過的方法
1.1 向上轉(zhuǎn)型
由子類類型轉(zhuǎn)換成父類類型,稱為向上轉(zhuǎn)型。父類引用指向子類對象
//父類類型 變量 = 子類類型實例; Pet pet = new Dog();//向上轉(zhuǎn)型
多態(tài)就是說一個父類可能有多個子類,每個子類都重寫了父類的方法(每個子類都有不同方法實現(xiàn)),當父類調(diào)用方法時,父類引用指向的是哪個子類,就執(zhí)行哪個子類的方法。形成了父類引用調(diào)用相同的方法時,有不同的實現(xiàn)。
父類引用只能調(diào)用父類中有的方法(子類繼承自父類的方法/重寫的方法)
父類引用不能調(diào)用子類擴展的方法(獨有的方法)
1.2 向下轉(zhuǎn)型
有父類類型轉(zhuǎn)換成子類類型,稱為向下轉(zhuǎn)型。必須要進行強制類型轉(zhuǎn)換。
注意:首先要判斷是否屬于要強轉(zhuǎn)的類型(instanceof),如果不屬于會報錯java.lang.ClassCastException
public static void main(String[] args) { // Dog dog = (Dog) new Pet();//向下轉(zhuǎn)型 java.lang.ClassCastException ? ?// System.out.println(new Pet() instanceof Dog); // false Pet pet = new Dog(); //向上轉(zhuǎn)型 Dog dog = null; if(pet instanceof Dog){ dog = (Dog) pet; //向下轉(zhuǎn)型 } System.out.println(pet.getClass()); //class com.itlaobing.demo.Dog System.out.println(pet instanceof Dog); //true }
1.3 實現(xiàn)多態(tài)的條件
①類之間存在繼承關(guān)系
②父類引用指向子類對象(向上轉(zhuǎn)型)
③子類要重寫父類的方法
1.4多態(tài)的特點與使用
特點:①可替換性②可擴充性③接口性④靈活性⑤簡化性
使用:①接口②重寫③抽象類方法
1.5多態(tài)的應(yīng)用
以父類類型作為方法的參數(shù)
父類類型出現(xiàn)的地方,子類都可以出現(xiàn)(使用)
public void toHost(Pet pet) { System.out.print("主人帶"); pet.toHospital(); } public static void main(String[] args) { Person person = new Person(); ? ? Dog dog = new Dog(); person.toHost(dog); ? ? Cat cat = new Cat(); person.toHost(cat); ? ? Pet pet = new Pet(); person.toHost(pet); }
使用父類型作為方法的返回值
public Pet getPet(int type) { if(1 == type) { return new Dog(); }else if(2 == type) { return new Cat(); }else { return new Pet(); } }
1.6 多態(tài)的注意點
public class Pet { public Pet getInstance() { System.out.println("pet getInstance()"); return new Pet(); } public static void staticMethod() { System.out.println("Pet staticMethod()"); } ? } ? class Dog extends Pet{ ? @Override public Dog getInstance() { System.out.println("Dog getInstance()"); return new Dog(); } public static void staticMethod() { System.out.println("Dog staticMethod()"); } }
public static void main(String[] args) { Pet p = new Dog(); p.getInstance(); // Dog getInstance() p.staticMethod();// Pet staticMethod() }
p.getInstance()
調(diào)用的是 Dog 類中的方法,因為在 Dog 類中重寫了 Pet 中的 getInstance()
方法,且調(diào)用實例方法看的是哪個對象調(diào)用就執(zhí)行哪個對象中的方法。也就是說 by Class
。
p.staticMethod()
調(diào)用的是 Pet 類中的方法,因為 staticMethod()
是 static 方法,屬于 類。雖然 Dog 類中隱藏了父類的方法,但是調(diào)用 static 方法看的是類型,也就是說 by type
,并且這和多態(tài)無關(guān)。
可以簡單的說,調(diào)用 static 方法看左邊。調(diào)用 實例方法 看右邊。
2.抽象類
public class Pet { public void toHospital() { System.out.println("寵物看病"); } } public class Dog extends Pet { public void porter() { System.out.println("看門狗"); } public void toHospital() { System.out.println("狗狗看病"); } } public class Cat extends Pet{ public void catchMouse() { System.out.println("貓捉老鼠"); } public void toHospital() { System.out.println("貓貓看病"); } }
從上面的代碼可以 發(fā)現(xiàn),父類中的的 toHospital()
方法并沒有實際意義,只是定義了一個規(guī)范,但是刪除之后,調(diào)用會報錯。失去了多態(tài)的特性。抽象類/抽象方法作用就是定義規(guī)范
2.1 abstract關(guān)鍵字
在 java 中,被 abstract 關(guān)鍵字修飾的類叫做抽象類,被 abstract 關(guān)鍵字修飾的方法叫做抽象方法。 抽象方法是沒有具體實現(xiàn)(沒有方法體)的。 abstract 不能和 final 一起使用。
2.2 抽象方法和普通方法的區(qū)別
[修飾符] 返回值類型 方法名([參數(shù)列表]){ //普通方法 //方法體 } [修飾符] abstract 返回值類型 方法名([參數(shù)列表]); //抽象方法
抽象方法沒有具體的實現(xiàn)(沒有方法體),所以,抽象不能執(zhí)行。
抽象方法是由繼承了抽象類的子類重寫后調(diào)用子類重寫的方法來執(zhí)行。
區(qū)別:
①抽象方法有abstract
修飾
②抽象方法沒有方法體
③抽象方法無法執(zhí)行
④抽象方法不能用private
修飾,因為被private
修飾的成員無法被繼承
2.3 抽象類和普通類的區(qū)別
[修飾符] abstract class 類名{} //抽象類 [修飾符] class 類名{} //普通類
抽象類中可以有普通方法
如果一個類繼承了抽象類,那么這個類必須重寫它的抽象方法,或者將類聲明為抽象類
抽象類是有構(gòu)造方法的,但是不能被實例化。因為抽象類中的抽象方法是沒有方法體的,導(dǎo)致抽象類不是一個完整的類,因此不允許實例化。
構(gòu)造方法、類方法( static )不能聲明為抽象( abstract )方法
抽象類除了不能被實例化以外,和普通了類沒有區(qū)別。定義抽象類是為了強迫子類實現(xiàn)抽象方 法,是定義規(guī)范的
區(qū)別:
①抽象類有abstract
修飾
②抽象類中可以有抽象方法,普通類不能有抽象方法,一個類中只要含有抽象方法,這個類就必須是抽象類,但是抽象類不一定含有抽象方法
③抽象類不能被實例化,需要抽象類變量引用其子類的對象
2.4 本質(zhì)
上層代碼定義規(guī)范,不用實現(xiàn)。具體業(yè)務(wù)實現(xiàn)由子類完成,調(diào)用者不用關(guān)心。
2.5 抽象類局限
子類重寫抽象類的抽象方法可能會出現(xiàn)代碼重復(fù)的情況,不符合代碼復(fù)用的要求
3.接口
約定好規(guī)范,然后按照規(guī)范來做。接口就是定義規(guī)范。
java 中的接口作用和生活中類似,它提供一種約定,使實現(xiàn)接口的類在形式上保持一致。
抽象類中可以有普通方法而接口中的方法都是抽象的,如果抽象類誒中的方法都是抽象方法,可以使用java提供的接口表示,因此也可以將接口看做是一個特殊的 抽象類 ,但是采用與抽象類完全不同的語法表示,并且兩者的設(shè)計理念也不同。
接口不能被 實例化,而且沒有構(gòu)造方法。
3.1 定義接口
[修飾符] interface 接口名{ //接口成員 [public] [static] [final] 數(shù)據(jù)類型 成員變量名 = 常量; public] [abstract] 返回值類型 方法名稱([參數(shù)列表]); }
接口的訪問權(quán)限是public
或package-acces
,與類的訪問權(quán)限類似
和抽象類不同,定義接口使用interface
關(guān)鍵字
接口中的方法默認是抽象方法,所以可以省略 abstract 修飾符
接口中的方法默認都是 public 的,所以可以省略 public
接口中的變量只能是靜態(tài)常量( static final ),所以可以省略 static final ,靜態(tài)常量在定義時就要 賦值,且不可變。
一個接口可以繼承其他接口,被繼承的接口稱為父接口。子接口將繼承父接口中聲明的常量和抽象方法
3.2 使用接口
使用接口和使用抽象類一樣,都是通過子類。子類通過 implements 關(guān)鍵字實現(xiàn)接口,實現(xiàn)接口就必須實現(xiàn) 接口中的抽象方法
public 類名 implements 接口名{ 實現(xiàn)方法 普通方法 屬性 }
一個類可以實現(xiàn)多個接口,接口之間使用,
隔開
實現(xiàn)接口的類必須實現(xiàn)接口中定義的所有抽象方法,即使不使用也必須實現(xiàn)它,通常用空方法體實現(xiàn)子類不需要的抽象方法,如果抽象方法有返回值,可返回默認值
接口的實現(xiàn)類中,可以有普通方法
實現(xiàn)的方法必須是 public
的,因為重寫方法時,權(quán)限不能縮小,只能大于等于被繼承的方法的訪問權(quán)限。
接口與接口之間是繼承關(guān)系,使用 extends 關(guān)鍵字。多個接口使用 ,
隔開,但是接口不能繼承類
3.3 實現(xiàn)多個接口
java 中繼承是單繼承,使用 extends 關(guān)鍵字;但是一個類可以實現(xiàn)多個接口,使用 implements ,多個 接口之間用 , 隔開。
一個類可以同時繼承和實現(xiàn)接口, extends 要在 implements 之前
3.4 jdk8接口新特性
在 jdk8.0 中 default 關(guān)鍵字可用于在接口中修飾方法(默認方法), default 修飾的方法可以有具體 實現(xiàn),也只能在接口中出現(xiàn)。 default 修飾的方法可以被重寫。如果一個類實現(xiàn)了兩個接口,這兩個接口又同時都包含了一個同名的default
方法,這種情況下編譯器會報錯。
接口中還可以有 static
修飾的方法,稱為靜態(tài)方法(類方法)。類方法可以直接使用接口名.方法名調(diào)用。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot集成Hutool防止XSS攻擊的兩種解決方法
XSS漏洞是生產(chǎn)上比較常見的問題,本文主要介紹了SpringBoot集成Hutool防止XSS攻擊的兩種解決方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-04-04Mybatis 入門之MyBatis環(huán)境搭建(第一篇)
Mybatis的前身叫iBatis,本是apache的一個開源項目, 2010年這個項目由apache software foundation 遷移到了google code,并且改名為MyBatis。這篇文章主要介紹了Mybatis入門第一篇之MyBaits環(huán)境搭建,需要的朋友參考下2016-12-12