1. 程式人生 > >09-面向物件--封裝+繼承

09-面向物件--封裝+繼承

一、封裝

1、封裝:隱藏物件的屬性和實現細節,僅對外提供公共的訪問方式(將類的某些資訊隱藏在類內部,不允許外部程式直接訪問,而是通過該類提供的方法來實現對隱藏資訊的操作和訪問)

2、封裝最常見最基本的動作:建立物件、呼叫成員、指揮物件做事情

3、規範:類中定義的成員變數通常都會被私有化(private),對外提供對應的set、get方法(賦值、獲取),set、get方法是為了對資料進行可控(可以在方法中對給定的資料進行邏輯判斷)。set方法返回值型別是void,get方法返回值型別和屬性型別相同

4、封裝的實現步驟:

(1)修改屬性的可見性 -- 設為private

(2)建立set、get方法 -- 用於屬性的讀寫

(3)在set、get方法中加入屬性控制語句 -- 對屬性值的合法性進行判斷

注意:不使用set、get方法,而是使用一般方法給屬性賦值是可以的,但不標準

5、封裝的好處:

(1)將變化隔離(隱藏類的例項細節,方便修改和實現) -- 類內部的結構可以自由修改

(2)便於使用(只能通過規定的方法訪問資料) -- 隱藏資訊好實現細節,有些資料不提供方法就訪問不了

(3)提高重用性

(4)提高安全性 -- 可以對成員進行更精確的控制(加if判斷)

6、一旦有屬性,幾乎都隱藏。對外提供方法的目的是可以對屬性進行控制

7、封裝的原則:

(1)將不需要對外提供的內容都隱藏起來

(2)把屬性都隱藏,提供公共方法對其訪問 -- 通常的表現形式。只要是類中的成員,不需要對外提供的,都可以隱藏(方法不是一定要對外提供)

8、私有(private)是封裝的一種體現,不私有一樣能封裝

9、Java中最小的封裝體是函式。類和框架都是封裝體 -- 只要是內部隱藏起來的都是封裝,這樣不需要了解細節,便於使用

二、繼承

1、何時定義繼承?

    當類與類之間存在著所屬關係時,就定義繼承。 eg:xxx is a yyy --> xxx extends yyy

2、繼承的好處和弊端:

好處:

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

(2)讓類與類之間產生關係,為第三個特徵多型提供前提(沒繼承,沒多型)

弊端:打破封裝性

3、父類是在不斷向上抽取的過程中產生的

4、java中支援單繼承,不直接支援多繼承(有多個直接父類)。因為多個父類中有相同成員,會產生呼叫的不確定性。但java對C++中的多繼承機制進行了改良,通過“多實現”的方式來體現

5、java支援多層繼承/多重繼承(C繼承B,B繼承A ...),也就是繼承體系。

     使用繼承體系時,(1)要檢視該體系中的最頂層類,瞭解該體系中最共性、最基本的功能(2)使用時,建立該體系中最子類的物件,因為最子類不僅有其父類的內容,還有自己特有的內容

6、判斷是否是繼承,看是否有extends關鍵字,而不是看類名

7、this代表一個本類物件的引用,super代表一個父類空間子類載入進記憶體時,因為extends,在方法區中,子類方法就持有了super引用,指向父類空間,所以子類可以獲取父類中的內容

注:super不代表父類物件,因為記憶體中自始至終只有一個子類物件,並沒有父類物件,所以super不能代表父類物件

(當本類的成員變數和區域性變數同名時,用this來區分;當子父類中的成員變數同名時,用super區分父類)

8、自己本空間中有,就不去外面找 -- 子類中有就不找父類,區域性中有就不找成員

9、子父類中成員變數記憶體分析:

(1)子類載入時,父類先於子類載入進記憶體

(2)父類沒有物件,隨著子類物件的建立,父類的成員變數存在於子類的物件中(兩個資料間只要有關係,他們就在一個物件中分空間儲存

(3)父類的成員變數在子類中持有一個super引用,子類的成員變數在子類中持有一個this引用

10、說明:

(1)父類中有的成員變數,子類一般直接拿來用,不用再重新定義一個

(2)通常情況下,成員變數都是私有的,對外提供set、get方法。子類直接呼叫set、get方法完成對父類的訪問

(3)子類對於父類私有的成員(成員變數和成員函式),也繼承過來了,儲存在子類物件中,用數字標識來標識其私有許可權。但外界不能直接訪問,只能通過內部間接的方式來訪問

(4)變數不涉及覆蓋

11、子父類中成員函式相同,會執行子類的函式,這種現象叫做覆蓋

12、函式的兩個特性:

(1)過載:同一個類中,函式名相同,引數列表不同,與返回值型別無關,與許可權無關

(2)覆蓋:子父類中,函式宣告(包括返回值型別、方法名、引數列表)完全一致,許可權子大父小(大蓋小)異常子小父大。覆蓋也叫重寫、覆寫

注:子父類中同名的成員函式可以在子父類中同時存在,是因為他們都有所屬,一個屬於父類,一個屬於子類

       方法過載是一個類的多型性表現,而方法覆蓋是子父類的多型性表現

13、覆蓋注意事項:

(1)子類方法覆蓋父類方法時,子類成員函式的許可權大於等於父類成員函式的許可權

注:如果父類的成員函式私有的,子類與其一模一樣的成員函式不叫覆蓋。因為覆蓋是子類不用的時候,父類可以使用,而私有的外面都不知道,無法使用

(2)靜態只能覆蓋靜態,或被靜態覆蓋。 即兩個方法中,只要有一個是static,另一個也必須是static,否則報錯

14、覆蓋的應用:

(1)通過一個類繼承原來的類的方式進行程式碼升級,升級後還是原來的類的一種,只是多了新功能

(2)當對一個類進行子類的擴充套件時,子類需要保留父類的功能宣告(函式宣告),定義子類中該功能的特有內容,此時使用覆蓋操作完成

15、繼承可以基本的提高程式的擴充套件性

16、子類在構造物件時,必須訪問父類的建構函式。所以,子類建構函式第一行,有一個預設的隱式語句:super();,用來呼叫父類的空參建構函式。如果不想用空參的,可以用super(引數列表)指定

注:子類中所有的建構函式,預設都會訪問父類中空引數的建構函式(預設的,不寫也有)。因為子類繼承了父類,獲取到父類中的內容。在使用父類內容之前要先看看父類是如何對自己的內容進行初始化的。如果要指定訪問父類哪個建構函式,需要顯示指定,用super(引數列表),且必須放在子類建構函式的第一行(父類的初始化動作要先完成)

17、關於子父類的建構函式:

(1)建構函式不能覆蓋,因為函式名不同

(2)建構函式沒有繼承過來。所以換了另一種方式來訪問,即在初始化時,可以通過super()訪問父類的建構函式

18、如果子類的構造函數出現了過載,且其中的某些建構函式中呼叫了this(引數列表);,此時this()要放在子類呼叫this()方法的建構函式的第一行,且該建構函式中不寫super()。但總會有一個建構函式執行super(引數列表)進行父類的初始化

注:this()和super()都只能定義在第一行,但只能有一個

eg:

class Zi extends Fu {
    Zi( ) {
        //super(); //至少有一個建構函式執行super()訪問父類的建構函式,進行父類初始化
        xxxxxx;
    }
    Zi( int x ) {
        this();    //使用this()呼叫本類建構函式。此建構函式中沒有super()
        xxxxxx;
    }
}//super(); //至少有一個建構函式執行super()訪問父類的建構函式,進行父類初始化
        xxxxxx;
    }
    Zi( int x ) {
        this();    //使用this()呼叫本類建構函式。此建構函式中沒有super()
        xxxxxx;
    }
}

19、在進行一個類的編寫時,它裡面都有一個隱式的建構函式,建構函式中有一句隱式的super()和return