小白學集合之看ArrayList和LinkedList原始碼
技術標籤:## java
抽象類和介面
抽象類
定義:抽象類前使用abstract關鍵字修飾,則該類為抽象類。
使用抽象類要注意以下幾點:
1. 抽象類是約束子類必須有什麼方法,而並不關注子類如何實現這些方法。
2. 抽象類應用場景:
a. 在某些情況下,某個父類只是知道其子類應該包含怎樣的方法,但無法準確知道這些子類如何實現這些方法(可實現動態多型)。
b. 從多個具有相同特徵的類中抽象出一個抽象類,以這個抽象類作為子類的模板,從而避免子類設計的隨意性。
3.抽象類定義抽象方法,只有宣告,不需要實現。抽象方法沒有方法體以分號結束,抽象方法必須用abstract關鍵字來修飾。如:
public abstract class Fruit {
//抽象方法 方法體以分號結束,只有宣告沒有實現
public abstract void price();
}
4.包含抽象方法的類是抽象類。抽象類中可以包含普通的方法,也可以沒有抽象方法。如:
public abstract class Fruit {
//抽象類裡面可以沒有抽象方法
public void message(){
System.out.println("我是抽象類的普通方法");
}//抽象類的普通方法
}
5.抽象類不能直接建立,可以定義引用變數來指向子類物件,來實現抽象方法。以上述的Fruit抽象類為例:
package OOP;
public class apple extends Fruit{
//繼承抽象類的子類必須重寫抽象方法
@Override
public void price() {
System.out.println("我是抽象類的子類,我重寫了抽象類的方法");
}
}
package OOP;
public abstract class Fruit {
//抽象方法 方法體以分號結束,只有宣告沒有實現
public abstract void price();
//抽象類裡面可以沒有抽象方法
public void message(){
System.out.println("我是抽象類的普通方法");
}//抽象類的普通方法
}
public class test {
public static void main(String[] args) {
//Fruit fruit = new Fruit(); 報錯,抽象類無法直接建立
Fruit fruit = new apple();//定義引用變數來指向子類
fruit.message();
fruit.price();
}
}
結果:
介面
1.概念
介面可以理解為一種特殊的類,由全域性常量和公共的抽象方法所組成。也可理解為一個特殊的抽象類,因為它含有抽象方法。
如果說類是一種具體實現體,而介面定義了某一批類所需要遵守的規範,介面不關心這些類的內部資料,也不關心這些類裡方法的實現細節,它只規定這些類裡必須提供的某些方法。(這裡與抽象類相似)
2.介面定義的基本語法
[修飾符] [abstract] interface 介面名 [extends父介面1,2…](多繼承){
0…n常量 (public static final)
0…n 抽象方法(public abstract)
}
其中[ ]裡的內容表示可選項,可以寫也可以不寫;介面中的屬性都是常量,即使定義時不新增public static final 修飾符,系統也會自動加上;介面中的方法都是抽象方法,即使定義時不新增public abstract修飾符,系統也會自動加上。
3.使用介面
一個類可以實現一個或多個介面,實現介面使用implements關鍵字。java中一個類只能繼承一個父類,是不夠靈活的,通過實現多個介面可以補充。
繼承父類實現介面的語法為:
[修飾符] class 類名 extends 父類 implements 介面1,介面2…{
類體部分//如果繼承了抽象類,需要實現繼承的抽象方法;要實現介面中的抽象方法
}
注意:如果要繼承父類,繼承父類必須在實現介面之前,即extends關鍵字必須在implements關鍵字前
補充說明:通常我們在命名一個介面時,經常以I開頭,用來區分普通的類。如:IPlayGame
以下我們來補充在上述抽象類中的例子,我們之前已經定義了一個抽象類Telephone和子類Phone,這裡我們再建立一個IPlayGame的介面,然後在原來定義的兩個類稍作修改,程式碼如下:
public interface IEatable {
//abstract 關鍵字可以省略,系統會自動加上
public String tester = "Chinese";
//static final關鍵字可以省略,系統會自動加上
public void result();
}
public class banana extends Fruit implements IEatable{
//繼承抽象類的子類必須重寫抽象方法
@Override
public void price() {
System.out.println("我有banana,我重寫了抽象類的方法,我將被測試者吃掉");
}
//一個類如果實現了一個介面,則要實現該介面的所有方法
@Override
public void result() {
System.out.println("我重寫了介面的方法,測試者來了");
}
}
public class test {
public static void main(String[] args) {
IEatable eatable = new banana();//用介面的引用指向子類的物件
eatable.result();//呼叫介面的方法
System.out.println(eatable.tester);//輸出介面的常量
}
}
執行結果:
4.介面和匿名內部類配合使用
介面在使用過程中還經常和匿名內部類配合使用。匿名內部類就是沒有沒名字的內部類,多用於關注實現而不關注實現類的名稱。
語法格式:
Interface i = new interface(){
pubulic void method{
System.out.println(“利用匿名內部類實現介面1”);
}
};
i.method();
另一種寫法:(直接把方法的呼叫寫在匿名內部類的最後,android開發常見)
Interface i = new interface(){
Public void method{
System.out.println(“利用匿名內部類實現介面1”);
}
}.method();
抽象類和介面的區別
我們在多型的學習過程中認識到抽象類和介面都是實現java多型特性的關鍵部分,兩者都包含抽象方法,只關注方法的宣告而不關注方法的具體實現,那麼這兩者又有什麼區別呢??我們在編寫java程式的時候又該如何抉擇呢?
參考博文:http://www.cnblogs.com/felixzh/p/5938544.html
(1)語法層面上的區別
1.一個類只能繼承一個抽象類,而一個類卻可以實現多個介面。
2.抽象類中的成員變數可以是各種型別的,而介面中的成員變數只能是public static final型別的;且必須給其初值,所以實現類中不能重新定義,也不能改變其值;抽象類中的變數預設是 friendly 型,其值可以在子類中重新定義,也可以重新賦值。
3.抽象類中可以有非抽象方法,介面中則不能有非抽象方法。
4.介面可以省略abstract 關鍵字,抽象類不能。
5.介面中不能含有靜態程式碼塊以及靜態方法,而抽象類可以有靜態程式碼塊和靜態方法;
(2)設計層面上的區別
1)抽象類是對一種事物的抽象,即對類抽象,而介面是對行為的抽象。抽象類是對整個類整體進行抽象,包括屬性、行為,但是介面卻是對類區域性(行為)進行抽象。舉個簡單的例子,飛機和鳥是不同類的事物,但是它們都有一個共性,就是都會飛。那麼在設計的時候,可以將飛機設計為一個類Airplane,將鳥設計為一個類Bird,但是不能將飛行 這個特性也設計為類,因此它只是一個行為特性,並不是對一類事物的抽象描述。此時可以將 飛行 設計為一個介面Fly,包含方法fly( ),然後Airplane和Bird分別根據自己的需要實現Fly這個介面。然後至於有不同種類的飛機,比如戰鬥機、民用飛機等直接繼承Airplane即可,對於鳥也是類似的,不同種類的鳥直接繼承Bird類即可。從這裡可以看出,繼承是一個 "是不是"的關係,而 介面 實現則是 "有沒有"的關係。如果一個類繼承了某個抽象類,則子類必定是抽象類的種類,而介面實現則是有沒有、具備不具備的關係,比如鳥是否能飛(或者是否具備飛行這個特點),能飛行則可以實現這個介面,不能飛行就不實現這個介面。
2)設計層面不同,抽象類作為很多子類的父類,它是一種模板式設計。而介面是一種行為規範,它是一種輻射式設計。什麼是模板式設計?最簡單例子,大家都用過ppt裡面的模板,如果用模板A設計了ppt B和ppt C,ppt B和ppt C公共的部分就是模板A了,如果它們的公共部分需要改動,則只需要改動模板A就可以了,不需要重新對ppt B和ppt C進行改動。而輻射式設計,比如某個電梯都裝了某種報警器,一旦要更新報警器,就必須全部更新。也就是說對於抽象類,如果需要新增新的方法,可以直接在抽象類中新增具體的實現,子類可以不進行變更;而對於介面則不行,如果介面進行了變更,則所有實現這個介面的類都必須進行相應的改動。
下面看一個網上流傳最廣泛的例子:門和警報的例子:門都有open( )和close( )兩個動作,此時我們可以定義通過抽象類和介面來定義這個抽象概念:
abstract class Door {
public abstract void open();
public abstract void close();
}
或者:
interface Door {
public abstract void open();
public abstract void close();
}
但是現在如果我們需要門具有報警alarm( )的功能,那麼該如何實現?下面提供兩種思路:
1)將這三個功能都放在抽象類裡面,但是這樣一來所有繼承於這個抽象類的子類都具備了報警功能,但是有的門並不一定具備報警功能;
2)將這三個功能都放在接口裡面,需要用到報警功能的類就需要實現這個介面中的open( )和close( ),也許這個類根本就不具備open( )和close( )這兩個功能,比如火災報警器。
從這裡可以看出, Door的open() 、close()和alarm()根本就屬於兩個不同範疇內的行為,open()和close()屬於門本身固有的行為特性,而alarm()屬於延伸的附加行為。因此最好的解決辦法是單獨將報警設計為一個介面,包含alarm()行為,Door設計為單獨的一個抽象類,包含open和close兩種行為。再設計一個報警門繼承Door類和實現Alarm介面。
interface Alram {
void alarm();
}
abstract class Door {
void open();
void close();
}
class AlarmDoor extends Door implements Alarm {
void oepn() {
//....
}
void close() {
//....
}
void alarm() {
//....
}
}
學習參考:
https://www.cnblogs.com/rove888/p/9936109.html