1. 程式人生 > >Java繼承、抽象、介面、多型

Java繼承、抽象、介面、多型


繼承

提取兩個類中的共性內容,生成一個父類,讓這連個類繼承這個父類

作用:

1)提高了程式碼的複用性

2)讓類與類之間產生了關係。有了這個關係,才有了多型的特性。

注意:千萬不要為了獲取其他類的功能,簡化程式碼而繼承。

     必須是類與類直接有所屬關係才可以繼承,所屬關係is a。

Java語言中:Java只繼承單繼承,不支援多繼承。

因為多繼承容易帶來安全隱患:當多個父類中定義了相同功能時,如果這些功能的實現不同,那麼子類物件在呼叫這個功能時不確定要執行哪個方法。

但是Java保留了這種機制,並用另一種體現形式來完成表示,那就是實現多個介面。

Java支援多層繼承。也就是一個繼承體系。

如何使用一個繼承體系中的功能?

想要使用體系,先查閱體系父類的描述,因為父類中定義的是該體系中的共性功能,通過了解共性功能,就能瞭解該體系的基本功能,該體系也就基本可以使用了。

那麼在具體呼叫時,要建立最子類的物件,為什麼呢?

1)是因為有可能父類是不能建立子類的,比如抽象類

2)建立子類物件可以使用更多的功能,包括基本的也包括特有的

總而言之,查閱父類功能,建立子類物件使用功能

聚合關係:比如球隊由許多球員聚集在一起

組合關係:比如身體的各個部分組成了一個人

子類出現後,類成員的特點:

1.成員變數

如果子類中出現非私有的同名成員變數時

子類要訪問本類中的變數,用this。

子類要訪問父類中的同名比那裡,用super

super的使用和this的使用幾乎一致。

this代表的是本類物件的引用,super代表的是父類物件的引用。

2.子父類中的函式

當子類出現和父類一模一樣的函式時,當子類物件呼叫該函式,會執行子類函式的內容,如同如來的函式被覆蓋一樣。

這種情況是函式的另一個特性:重寫(覆蓋)

當子類繼承父類,沿襲了父類的功能到子類中,但是子類雖具備該功能,但是功能的內容卻和父類不一致,

這時,沒有必要定義新功能,而是使用覆蓋特殊,保留父類的功能定義,並重寫子類功能。

重寫方法注意事項:

1)子類覆蓋父類,必須保證子類許可權大於等於父類許可權,才可以覆蓋,否則編譯失敗

2)靜態只能覆蓋靜態

注意:

過載:只看同名函式的引數列表

重寫:子父類方法要一模一樣

3.子父類中的建構函式

在對子類物件進行初始化時,父類的建構函式也會執行,那是因為子類的建構函式預設第一行有一條隱式的語句super(),

super()會訪問父類中空引數的建構函式,而且子類中所有的建構函式預設第一行是super()。如果父類沒有空引數的建構函式,那麼子類建構函式中必須顯示呼叫父類的有參構造方法。

為什麼子類一定要訪問父類中的建構函式?

因為父類中的資料,子類可以直接獲取,所以子類物件在建立時,要檢視父類是怎樣對這些資料進行初始化的。

所以子類在物件初始化時,要先訪問一下父類中的建構函式。

如果要訪問父類中指定的建構函式,可以通過手動定義super語句的方式來指定。

子類的例項化過程

結論:

子類中所有的建構函式,預設都會訪問父類中空引數的建構函式。

因為子類的每一個建構函式內第一行都有一句隱式的super()。

當父類中沒有空引數的建構函式時,子類必須手動通過super語句形式來指定要訪問父類中的建構函式。

當然子類的建構函式第一行也可以手動指定this語句來訪問本類中的建構函式。

子類中至少會有一個建構函式會訪問父類的建構函式。

final關鍵字:最終,作為一個修飾符

1)可以修飾類、函式、變數

2)被final修飾的類不可以被繼承。為了避免繼承,被子類複寫功能

3)被final修飾的函式不可以被複寫

4)被final修飾的變數是一個常量只能賦值一次,既可以是成員變數,也可以是區域性變數

當在描述事物時,一些資料的出現值是固定的,那麼這時為了增強閱讀性,都給這些值起個名字,方便於閱讀。

而這個值不需要改變,所以加上final修飾符。

作為常量,常量的書寫規範是所有字母都有大寫,如果由多個單片語成,則單詞間通過_連線。

5)內部類定義在類中的區域性位置上時,只能訪問該區域性被final修飾的區域性變數

當多個類中出現相同功能,但是功能主體不同時,這時可以進行向上抽取,只抽取功能定義,而不抽取功能主體。

抽象:看不懂

抽象類的特點:

1)抽象方法一定定義在抽象類中,抽象類中可以有普通方法

2)抽象方法和抽象類都必須被abstract關鍵字修飾

3)抽象類中不可以用new建立物件,因為呼叫抽象方法沒意義

4)抽象類中的方法要被使用,必須由子類複寫所有的方法後,建立子類物件呼叫。

如果子類只覆蓋了部分抽象方法,那麼該子類還是一個抽象類。

抽象類和一般類沒有太大的區別

該如何描述事物,就如何描述事物,只不過,該事物出現一些不確定的部分,也是該事物的功能,需要明確出現,但是無法定義主體,可以通過抽象方法來表示。

抽象類比一般類多了抽象函式,並且抽象類不可以例項化。

注意:抽象類中可以不定義抽象方法,這樣做僅僅是為了不讓該類建立物件

練習:

需求:獲取一段程式執行的時間

原理:獲取程式開始和結束的時間並相減

程式碼實現:

public abstract class GetTime {
	public final void getTime(){
		long start = System.currentTimeMillis();
		runCode();
		long end = System.currentTimeMillis();
		System.out.println("毫秒:"+(end-start));
	}
	public abstract void runCode();
}
class SubGetTime extends GetTime{

	@Override
	public void runCode() {
		for(int i=0; i<1000; i++)
			System.out.println(i);
		
	}
	public static void main(String[] args) {
		SubGetTime sgt = new SubGetTime();
		sgt.getTime();
	}
}
這裡用到了模板方法設計模式

什麼是模板方法設計模式?

在定義功能時,功能的一部分是確定的,但是有一部分是不確定的,而確定的部分在使用不確定的部分,那麼這時就將不確定的部分暴露出去,由該類的子類去完成。

介面:初步理解,可以認為是一種特殊的抽象類

當抽象類的方法都是抽象的,那麼該類可以通過介面的形式來表示。

class用於定義類

interface用於定義介面

介面定義時,格式特點:

1)介面中常見定義:常量,抽象方法

2)介面中的成員都有固定修飾符

常量:public static final

方法:public abstract

注意:介面中的成員都是public的

介面:不可以建立物件,因為有抽象方法,需要被子類實現,子類對介面中的抽象方法全都覆蓋後,子類才可以例項化,否則子類是一個抽象類

介面可以被類多實現,也是對多繼承不支援的轉換形式

介面可以繼承多個介面,但是多個介面中如果有同名同參數列表的函式,那麼這兩個函式的返回值必須相同

當一個類實現了多個介面時,同理

介面屬於擴充套件功能,繼承是必須具備的基本功能


多型:可以理解為事物存在的多種體現形態

1)多型的體現

父類的引用指向自己的子類物件

父類的引用也可以接收自己的子類物件

2)多型的前提

必須是類與類直接有關係,要麼繼承,要麼實現

通常還有一個前提:存在覆蓋

3)多型的好處

多型的出現大大提高了程式的擴充套件性

4)多型的弊端

提高了擴充套件性,但是隻能使用父類的引用訪問父類中的成員

5)多型的應用

向上轉型

Animal animal = new Cat();

向下轉型

if(animal instanceof Cat)

Cat cat = (Cat)animal;

不能將父類物件轉成子類型別,我們能轉換的是父類引用指向了自己的子類物件時,

該引用可以被提升,也可以被強制轉換。強轉時只能轉成相應的子類物件,而不是其他子類物件。多型自始自終都是子類物件在做著變化。

在多型非靜態成員函式中的特點:

在編譯時期:參閱引用型變數所屬的類中是否有呼叫的方法。如果有,編譯通過,如果沒有,編譯失敗。

在執行時期:參閱物件所屬的類中是否有呼叫的方法

總而言之:編譯看左邊,執行看右邊

在多型中,成員變數的特點:

無論編譯和執行都看左邊(父類)

在多型中,靜態成員函式的特點:

無論編譯和執行,都是參考左邊

Object:是所有物件的直接或者間接父類,該類中定義的肯定是所有物件都具備的基本功能。

Object類中已經提供了對物件是否相同的比較方法。

如果自定義類中也有比較相同的功能,沒有必要重新定義。

只要沿襲父類中的功能,建立自己特有比較內容即可,這就是覆蓋。