首頁>技術>

介面介面概述

介面和類一樣,也是一種引用資料型別,介面主要是用來定義常量和方法。

JDK7之前介面中可以定義常量和抽象方法JDK8以後介面中可以定義預設方法和靜態方法JDK9以後可以定義私有方法介面的定義和實現

定義類使用class關鍵字,而定義介面使用interface,介面編譯後也會產生對應的class檔案。介面不能透過new關鍵字來建立物件,需要使用類來實現介面,類實現介面的關鍵字是implements。

我們也可以定義一個子類可以繼承單個父類,實現多個介面。

類圖如下

首先定義一個父類CommonUserService,該類中包含兩個通用方法:doRegister()和doLogin()

當一個類實現多個介面時如果多個介面中同時存在相同的常量或者方法時可能會存在幾種衝突情況

常量:當多個父介面中有相同的常量,實現類不會繼承,也就不能訪問抽象方法:如果多個父介面中有相同的抽象方法,實現類重寫一個抽象方法即可。預設方法:因為預設方法可以被實現類繼承,因此多個父介面中存在相同的預設方法,實現類必須重寫一次預設方法。重寫的方法不需要加default關鍵字靜態方法:靜態方法只會提供給介面直接呼叫,所以對實現類無影響私有方法:由於私有方法只能在介面中直接呼叫,所以對實現類無影響介面多繼承時成員的訪問特點

類和類之間的關係是可以單繼承和多層繼承,Java的類不支援多繼承

介面和介面之間可以單繼承、多繼承和多層繼承,介面的繼承也是使用extends關鍵字

單繼承:一個介面繼承一個介面多繼承:一個介面同時繼承多個介面多層繼承:子類介面繼承父類介面,父類介面繼承爺爺類介面

以java.util.ArrayList為例,在它的類體系結構中,Collection介面就繼承了Iterable介面,這就是介面的單繼承,而List介面繼承了Collection介面,Colletion介面繼承了Iteable介面,這就是介面的多層繼承。介面的多繼承在專案開發時幾乎用不到。

當一個介面同時繼承多個父類介面時,多個父類介面如果存在相同的常量或者方法時可能會存在幾種衝突情況

常量:當多個父介面中有相同的常量,子類介面不會繼承,也無法訪問,直接使用父介面訪問父類的常量即可,因為介面中的常量是給介面直接使用抽象方法:如果多個父介面中有相同的抽象方法,子介面會繼承一個。預設方法:因為預設方法可以被實現類繼承,因此多個父介面中存在相同的預設方法,子介面必須重寫一次預設方法。重寫的方法需要加default關鍵字,因為介面的預設方法是public default。靜態方法:如果多個父介面中有多個相同的靜態方法,子類介面不會繼承,也無法訪問私有方法:由於私有方法只能在介面中直接呼叫,所以對子介面無影響實現類繼承父類又實現介面的訪問特點常量:當父類和多個父介面中有相同的常量,實現類不會繼承,也無法訪問抽象方法:如果父類和多個父介面中有相同的抽象方法,實現類必須重寫一次預設方法:如果父類和多個父介面中有相同的預設方法,實現類會優先呼叫父類的預設方法,如果父類沒有預設方法,會使用介面的預設方法。靜態方法:如果父類和多個父介面中有多個相同的靜態方法,實現類只會呼叫父類的靜態方法,因為介面的靜態方法不能被實現類繼承。私有方法:由於私有方法只能在父類和父介面中直接呼叫,所以對實現類無影響多型多型的定義和實現

多型(Polymorphism) 是繼封裝、繼承之後的面對象的第三大特性.多型指的是對於同一種行為,透過不同的事物,可以體現出來不同的形態。對映到Java中的多型就是指的同一個方法,對於不同的子類物件有不同的實現。多型有三種表現形式:普通父類多型、抽象父類多型和父介面多型。

實現多型要滿足3個前提條件

首先要有繼承或者實現關係,繼承就是子類繼承父類,實現就是子類實現父介面父類的引用指向子類的物件,例如之前使用 AbstractOrderTemplate jingdong =new JingDongOrderTemplate();方法的重寫,例如在JingDongOrderTemplate、TaobaoOrderTeamplate,PinDuoDuoOrderTemplate重寫了父類AbstractOrderTemplate的抽象方法,透過子類重寫父類的方法,實現同一個方法對於不同的子類物件有不同的實現。這樣多型才有意義。

這裡再舉一個例子:動物吃飯的多型,即抽象父類多型

首先定義一個抽象父類Animal,該類種包含一個抽象方法eat()

Dog子類,子類有一個位元組特有的lookHome()方法

多型時訪問成員的特點

多型時訪問成員指的是訪問成員變數和成員方法的特點,多型時訪問成員要考慮編譯期和執行期兩種情況

多型的好處和弊端

多型的好處可以提高程式碼的擴充套件性,透過父類的引用指向子類的物件也就意味著父類型別的物件可以接收該父類一切子類型別的物件,其典型的應用場景就是定義方法時的形參可以使用父類物件,而在呼叫方法時的實參可以傳遞該父類所有子類的物件。

如果此時Animal類新增了一個子類Panda

但是存在著無法訪問子類獨有的方法,因為編譯都無法透過,多型訪問非靜態成員方法時編譯時看父類。

返回值多型

一般返回值多型會結合形參多型使用。

返回值多型就是方法的返回值型別是父類型別。

局本內部類

區域性內部類是在方法中定義的,作用域僅限於方法,類似於區域性變數,生命週期從屬於方法,只能在方法中使用,區域性內部類很少使用。

非靜態內部類在其它類中訪問非內部類的成員變數和成員方法,需要建立內部類的物件訪問,因此如果有一個非靜態內部類物件那麼就一定存在對應的外部類物件,非靜態內部類物件單獨屬於外部類的某個物件。建立內部類物件的格式是 外部類名.內部類名 物件名 =new 外部類名().new 內部類名();

定義非靜態外部類Body,包含一個非靜態內部類Face,內部類預設是同包訪問許可權

在外部類中訪問非靜態內部類的成員,需要建立內部類的物件訪問。此時建立內部類的格式是內部類名 物件名 =new 內部類名();,但是外部類不能訪問內部類的私有成員。

非靜態內部類可以訪問外部類的一切成員,包含私有成員,如果非靜態內部類訪問外部類的私有成員,可以使用外部類.this.後面跟上成員變數或者是成員方法即可。

非靜態內部類不能包含靜態方法和靜態變數以及靜態程式碼塊。

靜態內部類可以看作外部類的一個靜態成員,也就是使用static修飾的非靜態內部類,靜態內部類可以範圍外部類的靜態成員,不能訪問外部類的普通成員。在JDK的原始碼java.lang.Long類中就使用了靜態內部類來維護一個快取,不過它是一個私有的,因此只能在java.lang.Long類中使用。

靜態內部類還有一個最佳實踐:實現執行緒安全的單例模式

單例模式就是保證類只有一個物件例項其實現方法是提供一個私有化的構造器,那樣就不能在當前類以外的地方建立該物件的例項然後提供一個靜態的獲取例項的方法,如果外部想要建立該類的物件,直接呼叫該靜態方法即可。內部類由於類載入機制,具有先天的執行緒安全性,因此是單例模式的最佳實現方式。

匿名內部類

匿名內部類可以定義在類或者介面中,適合那種只需要使用一次的類,比如監聽鍵盤等操作。匿名內部類沒有訪問修飾符,沒有構造方法。

匿名內部類是繼承了父類的匿名子類物件例如Dog繼承了Animal父類,那麼Dog類的物件就是繼承了Animal類的子類物件,而如果是匿名內部類就是繼承了父類Animal的匿名子類物件。匿名內部類主要是用於簡化程式碼

例如如果是新增一個小動物類:Monkey繼承自抽象父類Animal,重寫eat()抽象方法。如果不使用匿名內部類,我們需要建立這樣做

首先建立一個猴子子類繼承自Animal父類,然後重寫eat()方法

有了匿名內部類後,可以直接在main方法中建立Animal的子類物件,實現和剛才等價的效果。其區別是Animal類物件的作用域僅僅侷限在main方法,出了main方法就無法使用了。

匿名內部類是實現了父介面的匿名實現類物件

除了類可以建立匿名子類物件以外,介面按照同樣的方式也可以建立匿名子類實現類

Java8以後支援了lambda表示式,相比匿名內部類可以實現更加簡潔的語法,後續會詳細介紹使用。

測試程式碼 內部類的編譯路徑對比之前的非靜態內部類,匿名內部類生成的位元組碼在$後跟上了數字1,而非靜態內部類是類名。

引用型別在專案開發中的使用

到目前為止已經學習的引用資料型別包含陣列、類、抽象類、介面四種類型,不過後續專案開發中很少會使用陣列。那為什麼還要學習陣列呢?

因為陣列是引用資料型別,學習陣列可以瞭解JVM的記憶體模型,再學類、物件的記憶體模型時可以加深印象,因為引用型別的記憶體模型是類似的。瞭解了陣列,就可以瞭解JDK提供的ArrayList實現原理引用資料型別(類、抽象類、介面)在日常開發中經常會作為成員變數, 方法的引數、返回值中使用。引用資料型別在作為方法的引數、返回值時傳遞的都是地址值。

19
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 精美Bootstrap電子商務模板電商網站