複習7:三大特性

三大特性

  • 封裝
  • 繼承
  • 多態

三大特性:封裝

封裝是什麼

將成員變量私有化,並且提供對應的公共訪問方法

封裝的優點
  • 提高代碼的複用性
  • 提高代碼的可閱讀性
  • 隱藏核心實現的邏輯代碼,簡化外部邏輯,並且阻止來自外部的隨意訪問
  • 實現代碼與功能的一對一匹配
封裝的實現

核心:

  • 成員變量私有化:private
  • 提供公共訪問方法:getter/setter

注意:只有私有化後的成員變量才能叫做屬性

示例:

package day20191103;

public class Demo01 {
	private int a;
	private int b;
	public void Demo01() {
		
	}
	public int getA() {
		return a;
	}
	public void setA(int a) {
		this.a = a;
	}
	public int getB() {
		return b;
	}
	public void setB(int b) {
		this.b = b;
	}
	
}
實體類的規範

實體類是什麼:具有實際意義的類叫做實體類,又叫JavaBean

實體類有什麼:

  • 屬性
  • 無參構造器
  • getter/setter

JavaBean的規範

  • 命名規範:單個單詞首字母大寫,多個單詞的組合遵循駝峯命名法
  • 成員變量私有化,提供getter/setter方法
  • 提供無參構造器
  • 重寫equals()和hashCode()
  • 重寫toString()

注意:業務代碼不能寫在實體類中


三大特性:繼承

繼承是什麼

子類繼承父類,子類擁有父類所有(公開的)成員屬性和成員方法(構造器除外),同時子類也可以擁有自己特有的成員屬性和成員方法

注意:

  • 若子類自己的成員屬性與父類同名,則父類的成員屬性被覆蓋
  • 若子類自己的成員方法與父類同名,則發生方法重寫
繼承的作用
  • 提高代碼的複用性
    • 提取公共特徵
  • 可以在父類的基礎上進行擴展
繼承的使用

關鍵詞:extends

示例:

class Animal{
    String name;
    int age;
    public void sleep(){
        
    }
    public void eat(){
        
    }
}
class People extends Animal{
    String bitthday;
    public void study(){
        
    }
}
public static void main(String[] args){
    People p = new People();
    p.study();
    //子類可以擁有父類的成員變量和成員方法
    p.sleep();
}
繼承的特點
  • 繼承具有傳遞性,即子類繼承父類的同時,也會繼承父類的父類(爺爺-爸爸-兒子)

  • 一個父類可以有多個子類(一個爸爸可以有多個兒子)

  • 一個子類只能有一個父類(一個兒子只能有一個爸爸)

  • 如果一個類沒有繼承任何類,那麼這個類默認繼承Object類,所以每個類都有父類(每個兒子必定有一個爸爸)

  • 結合第一點和第四點,我們可以得知:所有類都繼承了Object類。這個繼承可以分爲兩種:

    • 直接繼承:子類直接繼承Object類
    class Son extends Object{
        //直接繼承
    }
    
    • 間接繼承:子類的父類(或最高代)繼承Object類
    class Father{
        
    }
    
    class Son extends Father{
        //子類繼承父類,父類繼承Object類
    }
    
子類內存在堆中的表現形式

子類內存在堆中分爲兩個部分

  • 父類對象
  • 子類對象

這兩個對象在new操作時被創建,對象中有各自成員屬性與成員方法。在調用成員屬性和成員方法時,遵循就近原則:子類對象中存在同名的屬性或方法時,則調用子類中的屬性和方法;否則,就調用父類對象中的屬性或方法(方法重寫的原理)。

內存示意圖如下:

子類內存

子類調用父類成員

關鍵字:super

super是什麼

  • 表示父類對象,與this用法類似、意義不同

super的作用

  • 調用父類(公開的)構造器:super(參數列表)
  • 調用父類(公開的)成員屬性:super.屬性名()
  • 調用父類(公開的)成員方法:super.方法名()

super調用自身構造器的注意點

  • 只能放在構造器中
  • 必須是第一行代碼

注意:

  • 每一個類的構造器中都有一個隱含的super(),可以被自定義的**super(參數)**覆蓋
    • 在子類實例化對象時,一定會在構造自身之前先構造一個父類對象
    • 當父類只有有參構造器時,子類構造器將出現錯誤。因此,爲了方便繼承,每一個父類都必須添加無參構造器

三大特性:多態

多態

多態的表現形式

  • 重載
  • 重寫

多態的前提條件

  • 具有繼承關係的父、子類(實現抽象類也算)
方法重載

方法重載的條件

  • 同一個類中
  • 方法名相同、參數列表不同的方法構成重載
    1. 參數個數不同
    2. 參數個數相同,參數類型不同
    3. 參數個數相同,參數類型相同,相同類型的參數順序不同

注意1:

  • 參數列表的異同判斷與參數名稱無關
  • 方法重載與返回值類型無關
  • 方法重載與訪問控制符無關
  • 調用方法時,根據傳入的參數確定調用哪一個重載方法

方法重載的作用

  • 提高代碼的複用性
  • 提高代碼的閱讀性
  • 使代碼更加規範
方法重寫

方法重寫的條件:

  • 在子類中(繼承/抽象)
  • 返回值類型相同或是父類返回值類型的子類,方法名、參數列表必須相同
  • 訪問控制權限不能比父類窄

方法重寫的作用:

  • 提高代碼的複用性
  • 體現不同對象之間的差異性

示例:

package day20191029;

public class Demo01 {
	public static void main(String[] args) {
		Son son = new Son();
		son.method();
	}
}
class Father{
	public Father( ) {
		
	}
	public void method() {
		System.out.println("我是父類方法");
	}
}
class Son extends Father{
	public Son() {
		
	}
	public void method() {
		System.out.println("我是子類方法");
	}
}

注意:子類調用方法時,遵循就近原則

向上造型

向上造型是什麼:父類類型的引用變量接收子類類型的對象,是多態的體現

  • 示例:Father father = new Son();

向上造型中的相關概念

  • 編譯時類型:編譯時,編譯器眼中的變量類型(Father father部分)
  • 運行時類型:運行時,虛擬機眼中的變量類型(**new Son()**部分 )

編譯器認爲father的類型是Father,但是在運行時,虛擬機認爲father的類型是Son

向上造型中的多態體現

  • 編譯時類型決定對象能調用哪些方法:通俗地說,father能"."出Father中的所有方法
  • 運行時類型決定對象調用的方法內容:如果father調用的方法在Son中被重寫,則調用Son中的方法;否則,調用Father中的方法
  • 示例:
package day20191029;

public class Demo01 {
	public static void main(String[] args) {
		Father father = new Son();
		father.method();//method()在子類中被重寫,所以此時調用的是子類中的方法
	}
}
class Father{
	public Father( ) {
		
	}
	public void method() {
		System.out.println("我是父類方法");
	}
}
class Son extends Father{
	public Son() {
		
	}
	public void method() {
		System.out.println("我是子類方法");
	}
}

注意:只有調用被重寫的方法才能體現多態,如果調用未被重寫的方法,則無法體現多態

向上造型的類型轉換

轉換的條件

  • 必須有直接繼承關係
  • 運行時類型相同或子類轉換成父類

父類不能轉換成子類,而子類能轉換成父類的原因:子類中除了繼承自父類的成員屬性和成員方法,還有屬於自己的屬性和方法。父類轉換成子類時,引用變量的編譯時類型變成了子類類型,而運行時類型依然是父類類型,由於編譯時類型的特性,轉換後的引用變量能使用子類特有的屬性和方法,但是實際運行時父類中並沒有這些屬性和方法,於是發生了報錯;而子類轉換成父類就沒有這個問題,因爲子類有父類所有(公開的)成員屬性和成員方法。

示例:

package day20191029;

public class Demo01 {
	public static void main(String[] args) {
		
		Father father1 = new Son();
		Son son1 = (Son)father1;
		son1.method();
		
		Son son2 = new Son();
		Father father2 = (Father)son2;
		
        //編譯通過,但是運行後拋出ClassCastException
		Father father = new Father();
		Son son3 = (Son)father;
		son3.method2();
	}
}

class Father{
	public Father( ) {
		
	}
	public void method() {
		System.out.println("我是父類方法1");
	}
	public void method2() {
		System.out.println("我是父類方法2");
	}
}

class Son extends Father{
	public Son() {
		
	}
	public void method() {
		System.out.println("我是子類方法1");
	}
}

注意:強制類型轉換屬於編譯時語法,該語法只在編譯時有效,運行時取決於運行時類型。因此纔會發生編譯通過,但是運行報錯。

親子鑑定

關鍵字:instanceof

  • 作用:判斷一個引用變量是否屬於某個類型(取決於運行時類型),返回值是布爾類型
  • 使用示例:father instanceof Father

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章