1. 程式人生 > >JavaSE 學習筆記之繼承(五)

JavaSE 學習筆記之繼承(五)

內容 訪問 類繼承 mil 抽象方法 ted 內部 -- 中一

繼 承(面向對象特征之一)

好處:

1:提高了代碼的復用性。

2:讓類與類之間產生了關系,提供了另一個特征多態的前提。

父類的由來:其實是由多個類不斷向上抽取共性內容而來的。

java中對於繼承,java只支持單繼承。java雖然不直接支持多繼承,但是保留了這種多繼承機制,進行改良。

單繼承:一個類只能有一個父類。

多繼承:一個類可以有多個父類。

為什麽不支持多繼承呢?

因為當一個類同時繼承兩個父類時,兩個父類中有相同的功能,那麽子類對象調用該功能時,運行哪一個呢?因為父類中的方法中存在方法體。

但是java支持多重繼承。A繼承B B繼承C C繼承D。

多重繼承的出現,就有了繼承體系。體系中的頂層父類是通過不斷向上抽取而來的。它裏面定義的該體系最基本最共性內容的功能。

所以,一個體系要想被使用,直接查閱該系統中的父類的功能即可知道該體系的基本用法。那麽想要使用一個體系時,需要建立對象。建議建立最子類對象,因為最子類不僅可以使用父類中的功能。還可以使用子類特有的一些功能。

簡單說:對於一個繼承體系的使用,查閱頂層父類中的內容,創建最底層子類的對象。

子父類出現後,類中的成員都有了哪些特點:

1:成員變量。

當子父類中出現一樣的屬性時,子類類型的對象,調用該屬性,值是子類的屬性值。

如果想要調用父類中的屬性值,需要使用一個關鍵字:super

This代表是本類類型的對象引用。

Super代表是子類所屬的父類中的內存空間引用。

註意:子父類中通常是不會出現同名成員變量的,因為父類中只要定義了,子類就不用在定義了,直接繼承過來用就可以了。

2:成員函數。

當子父類中出現了一模一樣的方法時,建立子類對象會運行子類中的方法。好像父類中的方法被覆蓋掉一樣。所以這種情況,是函數的另一個特性:覆蓋(復寫,重寫)

什麽時候使用覆蓋呢?當一個類的功能內容需要修改時,可以通過覆蓋來實現。

3:構造函數。

發現子類構造函數運行時,先運行了父類的構造函數。為什麽呢?

原因:子類的所有構造函數中的第一行,其實都有一條隱身的語句super();

super(): 表示父類的構造函數,並會調用於參數相對應的父類中的構造函數。而super():是在調用父類中空參數的構造函數。

為什麽子類對象初始化時,都需要調用父類中的函數?(為什麽要在子類構造函數的第一行加入這個super()?)

因為子類繼承父類,會繼承到父類中的數據,所以必須要看父類是如何對自己的數據進行初始化的。所以子類在進行對象初始化時,先調用父類的構造函數,這就是子類的實例化過程

註意:子類中所有的構造函數都會默認訪問父類中的空參數的構造函數,因為每一個子類構造內第一行都有默認的語句super();

如果父類中沒有空參數的構造函數,那麽子類的構造函數內,必須通過super語句指定要訪問的父類中的構造函數。

如果子類構造函數中用this來指定調用子類自己的構造函數,那麽被調用的構造函數也一樣會訪問父類中的構造函數。

問題:super()和this()是否可以同時出現的構造函數中。

兩個語句只能有一個定義在第一行,所以只能出現其中一個。

super()或者this():為什麽一定要定義在第一行?

因為super()或者this()都是調用構造函數,構造函數用於初始化,所以初始化的動作要先完成。

繼承的細節:

什麽時候使用繼承呢?

當類與類之間存在著所屬關系時,才具備了繼承的前提。a是b中的一種。a繼承b。狼是犬科中的一種。

英文書中,所屬關系:" is a "

註意:不要僅僅為了獲取其他類中的已有成員進行繼承。

所以判斷所屬關系,可以簡單看,如果繼承後,被繼承的類中的功能,都可以被該子類所具備,那麽繼承成立。如果不是,不可以繼承。

細節二:

在方法覆蓋時,註意兩點:

1:子類覆蓋父類時,必須要保證,子類方法的權限必須大於等於父類方法權限可以實現繼承。否則,編譯失敗。

2:覆蓋時,要麽都靜態,要麽都不靜態。 (靜態只能覆蓋靜態,或者被靜態覆蓋)

繼承的一個弊端:打破了封裝性。對於一些類,或者類中功能,是需要被繼承,或者復寫的。

這時如何解決問題呢?介紹一個關鍵字,final:最終。

final特點:

1:這個關鍵字是一個修飾符,可以修飾類,方法,變量。

2:被final修飾的類是一個最終類,不可以被繼承。

3:被final修飾的方法是一個最終方法,不可以被覆蓋。

4:被final修飾的變量是一個常量,只能賦值一次。

其實這樣的原因的就是給一些固定的數據起個閱讀性較強的名稱。

不加final修飾不是也可以使用嗎?那麽這個值是一個變量,是可以更改的。加了final,程序更為嚴謹。常量名稱定義時,有規範,所有字母都大寫,如果由多個單詞組成,中間用 _ 連接。

抽象類:abstract

抽象:不具體,看不明白。抽象類表象體現。

在不斷抽取過程中,將共性內容中的方法聲明抽取,但是方法不一樣,沒有抽取,這時抽取到的方法,並不具體,需要被指定關鍵字abstract所標示,聲明為抽象方法。

抽象方法所在類一定要標示為抽象類,也就是說該類需要被abstract關鍵字所修飾。

抽象類的特點:

1:抽象方法只能定義在抽象類中,抽象類和抽象方法必須由abstract關鍵字修飾(可以描述類和方法,不可以描述變量)。

2:抽象方法只定義方法聲明,並不定義方法實現。

3:抽象類不可以被創建對象(實例化)。

4:只有通過子類繼承抽象類並覆蓋了抽象類中的所有抽象方法後,該子類才可以實例化。否則,該子類還是一個抽象類。

抽象類的細節:

1:抽象類中是否有構造函數?有,用於給子類對象進行初始化。

2:抽象類中是否可以定義非抽象方法?

可以。其實,抽象類和一般類沒有太大的區別,都是在描述事物,只不過抽象類在描述事物時,有些功能不具體。所以抽象類和一般類在定義上,都是需要定義屬性和行為的。只不過,比一般類多了一個抽象函數。而且比一般類少了一個創建對象的部分。

3:抽象關鍵字abstract和哪些不可以共存?final , private , static

4:抽象類中可不可以不定義抽象方法?可以。抽象方法目的僅僅為了不讓該類創建對象。

-----------------------------------------------------------------------------------------------

模板方法設計模式:

解決的問題:當功能內部一部分實現時確定,一部分實現是不確定的。這時可以把不確定的部分暴露出去,讓子類去實現。

abstract class GetTime{

public final void getTime(){ //此功能如果不需要復寫,可加final限定

long start = System.currentTimeMillis();

code(); //不確定的功能部分,提取出來,通過抽象方法實現

long end = System.currentTimeMillis();

System.out.println("毫秒是:"+(end-start));

}

public abstract void code(); //抽象不確定的功能,讓子類復寫實現

}

class SubDemo extends GetTime{

public void code(){ //子類復寫功能方法

for(int y=0; y<1000; y++){

System.out.println("y");

}

}

}

JavaSE 學習筆記之繼承(五)