1.8 封裝、繼承、多態

一、封裝

面向對象編程語言是對客觀世界的模擬,客觀世界裏成員變量都是隱藏在對象內部的,外界無法直接操作和修改。封裝可以被認爲是一個保護屏障,防止該類的代碼和數據被其他類隨意訪問。要訪問該類的數據,必須通過指定的方式。適當的封裝可以讓代碼更容易理解與維護,也加強了代碼的安全性。

將屬性隱藏起來,提供公共方法訪問某個屬性。

1、private關鍵字

  1. private是一個權限修飾符,代表最小權限。
  2. 可以修飾成員變量和成員方法。
  3. 被private修飾後的成員變量和成員方法,只在本類中才能訪問。

2、this關鍵字

this代表所在類的當前對象的引用(地址值),即對象自己的引用。

方法被哪個對象調用,方法中的this就代表那個對象。誰在調用,this就代表誰。

this使用格式

this.成員變量名;

使用 this 修飾方法中的變量,解決成員變量被隱藏的問題,代碼如下:

public class Student {
  private String name;

  public void setName(String name) {
    //name = name;
    this.name = name;
  }

  public String getName() {
    return name;
  }
}

3、構造方法

當一個對象被創建時候,構造方法用來初始化該對象,給對象的成員變量賦初始值。

無論你與否自定義構造方法,所有的類都有構造方法,因爲Java自動提供了一個無參數構造方法,一旦自己定義了構造方法,Java自動提供的默認無參數構造方法就會失效。

構造方法的定義格式

修飾符 構造方法名(參數列表){
	// 方法體
}

構造方法的寫法上,方法名與它所在的類名相同。它沒有返回值,所以不需要返回值類型,甚至不需要void。使用構造方法後,代碼如下:

public class Student {
  private String name;
  private int age;
  // 無參數構造方法
  public Student() {} 
  // 有參數構造方法
  public Student(String name,int age) {
    this.name = name;
    this.age = age; 
  }
}

注意事項:

  1. 如果你不提供構造方法,系統會給出無參數構造方法。
  2. 如果你提供了構造方法,系統將不再提供無參數構造方法。
  3. 構造方法是可以重載的,既可以定義參數,也可以不定義參數。

4、標準代碼

JavaBean 是 Java語言編寫類的一種標準規範。符合JavaBean 的類,要求類必須是具體的和公共的,並且具有無參數的構造方法,提供用來操作成員變量的setget 方法。

public class ClassName{
  //成員變量
  //構造方法
  //無參構造方法【必須】
  //有參構造方法【建議】
  //成員方法	
  //getXxx()
  //setXxx()
}

編寫符合JavaBean 規範的類,以學生類爲例,標準代碼如下:

public class Student {
  //成員變量
  private String name;
  private int age;

  //構造方法
  public Student() {}

  public Student(String name,int age) {
    this.name = name;
    this.age = age;
  }

  //成員方法
  publicvoid setName(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  publicvoid setAge(int age) {
    this.age = age;
  }

  publicint getAge() {
    return age;
  }
}

測試類,代碼如下:

public class TestStudent {
  public static void main(String[] args) {
    //無參構造使用
    Student s= new Student();
    s.setName("柳巖");
    s.setAge(18);
    System.out.println(s.getName()+"---"+s.getAge());

    //帶參構造使用
    Student s2= new Student("趙麗穎",18);
    System.out.println(s2.getName()+"---"+s2.getAge());
  }
}

二、繼承

1、概述

多個類中存在相同屬性和行爲時,將這些內容抽取到單獨一個類中,那麼多個類無需再定義這些屬性和行爲,只要繼承那一個類即可。如圖所示:

在這裏插入圖片描述
其中,多個類可以稱爲子類,單獨那一個類稱爲父類超類(superclass)或者基類

繼承描述的是事物之間的所屬關係。例如,圖中兔子屬於食草動物,食草動物屬於動物。可見,父類更通用,子類更具體。我們通過繼承,可以使多種事物之間形成一種關係體系。

2、定義

繼承:就是子類繼承父類的屬性行爲,使得子類對象具有與父類相同的屬性、相同的行爲。子類可以直接訪問父類中的非私有的屬性和行爲。

優點:

  1. 提高代碼的複用性
  2. 類與類之間產生了關係,是多態的前提

3、格式

通過 extends 關鍵字,可以聲明一個子類繼承另外一個父類,定義格式如下:

class 父類 {
	...
}

class 子類 extends 父類 {
	...
}

4、繼承後的特點

成員變量:

子父類中出現了同名的成員變量時,在子類中需要訪問父類中非私有成員變量時,需要使用super 關鍵字,修飾父類成員變量。

構造方法:

當類之間產生了關係,其中各類中的構造方法,又產生了哪些影響呢?

首先我們要回憶兩個事情,構造方法的定義格式和作用。

  1. 構造方法的名字是與類名一致的。所以子類是無法繼承父類構造方法的。
  2. 構造方法的作用是初始化成員變量的。所以子類的初始化過程中,必須先執行父類的初始化動作。子類的構造方法中默認有一個super() ,表示調用父類的構造方法,父類成員變量初始化後,纔可以給子類使用。

成員方法:

成員方法不重名

如果子類父類中出現不重名的成員方法,這時的調用是沒有影響的

成員方法重名——重寫(Override)

如果子類父類中出現重名的成員方法,需要進行方法重寫(Override)

  • 方法重寫 :子類中出現與父類一模一樣的方法時,需要重寫父類的方法。

子類可以根據需要,定義特定於自己的行爲。既沿襲了父類的功能名稱,又根據子類的需要重新實現父類方法,從而進行擴展增強。

class Phone {
	public void showNum(){
		System.out.println("來電顯示號碼");
	}
}

extends:

//智能手機類
class NewPhone extends Phone {
	
	//重寫父類的來電顯示號碼功能,並增加自己的顯示姓名和圖片功能
	public void showNum(){
		//調用父類已經存在的功能使用super
		super.showNum();
		//增加自己特有顯示姓名和圖片功能
		System.out.println("顯示來電姓名");
		System.out.println("顯示頭像");
	}
}

Test:

public class ExtendsDemo06 {
	public static void main(String[] args) {
      	// 創建子類對象
      	NewPhone np = new NewPhone()// 調用子類重寫的方法
      	np.showNum();

	}
}

注意事項:

  1. 子類方法覆蓋父類方法,必須要保證權限大於等於父類權限。
  2. 子類方法覆蓋父類方法,返回值類型、函數名和參數列表都要一模一樣。
  3. 子類方法覆蓋父類方法,子類的返回值類型要是父類返回值類型的子類。

5、super和this區別

父類空間優先於子類對象產生

在每次創建子類對象時,先初始化父類空間,再創建其子類對象本身。目的在於子類對象中包含了其對應的父類空間,便可以包含其父類的成員,如果父類成員非private修飾,則子類可以隨意使用父類成員。代碼體現在子類的構造方法調用時,一定先調用父類的構造方法。理解圖解如下:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-gggegzp7-1592739295232)(img/2.jpg)]

super和this的含義

  • super :代表父類的存儲空間標識(可以理解爲父親的引用)。

  • this :代表當前對象的引用(誰調用就代表誰)。

特點:

  • 子類的每個構造方法中均有默認的super(),調用父類的空參構造。
  • 手動調用父類構造會覆蓋默認的super()。
  • super() 和 this() 都必須是在構造方法的第一行,所以不能同時出現。

6、繼承的特點

Java只支持單繼承。
在這裏插入圖片描述

三、多態

1、概述

  • 多態: 是指同一行爲,具有多個不同表現形式。

前提:

  1. 繼承或者實現【二選一】
  2. 方法的重寫【意義體現:不重寫,無意義】
  3. 父類引用指向子類對象【格式體現】

2、格式

多態體現的格式:

父類類型 變量名 = new 子類對象;
變量名.方法名();

代碼:

Fu f = new Zi();
f.method();

當使用多態方式調用方法時,首先檢查父類中是否有該方法,如果沒有,則編譯錯誤;
如果有,執行的是子類重寫後方法。

3、多態的應用

實際開發的過程中,父類類型作爲方法形式參數,傳遞子類對象給方法,進行方法的調用,更能體現出多態的擴展性與便利。

定義父類:

public abstract class Animal {  
    public abstract void eat();  
}  

定義子類:

class Cat extends Animal {  
    public void eat() {  
        System.out.println("喫魚");  
    }  
}  

class Dog extends Animal {  
    public void eat() {  
        System.out.println("喫骨頭");  
    }  
}

定義測試類:

public class Test {
    public static void main(String[] args) {
        // 多態形式,創建對象
        Cat c = new Cat();  
        Dog d = new Dog(); 

        showAnimalEat(c);
        showAnimalEat(d); 
    }

    public static void showAnimalEat (Animal a){
        a.eat();
    }
}

由於多態特性的支持,showAnimalEat方法的Animal類型,是Cat和Dog的父類類型,父類類型接收子類對象,當然可以把Cat對象和Dog對象,傳遞給方法。

多態的好處,可以使程序編寫的更簡單,並有良好的擴展。

4、向上轉型和向下轉型

  • 向上轉型:多態本身是子類類型向父類類型向上轉換的過程,這個過程是默認的。

當父類引用指向一個子類對象時。

父類類型  變量名 = new 子類類型();
如:Animal a = new Cat();
  • 向下轉型:父類類型向子類類型向下轉換的過程,這個過程是強制的。

一個已經向上轉型的子類對象,將父類引用轉爲子類引用,可以使用強制類型轉換的格式。

子類類型 變量名 = (子類類型) 父類變量名;:Cat c =(Cat) a;

5、ClassCastException異常

代碼能通過編譯,但是運行時,卻報出了 ClassCastException ,類型轉換異常!這是因爲,明明創建了Cat類型對象,運行時,當然不能轉換成Dog對象的。這兩個類型並沒有任何繼承關係,不符合類型轉換的定義。

爲了避免ClassCastException的發生,Java提供了 instanceof 關鍵字,給引用變量做類型的校驗。

變量名 instanceof 數據類型 
如果變量屬於該數據類型,返回true。
如果變量不屬於該數據類型,返回false

所以,轉換前,我們最好先做一個判斷,代碼如下:

public class Test {
    public static void main(String[] args) {
        // 向上轉型  
        Animal a = new Cat();  
        a.eat();               // 調用的是 Cat 的 eat

        // 向下轉型  
        if (a instanceof Cat){
            Cat c = (Cat)a;       
            c.catchMouse();        // 調用的是 Cat 的 catchMouse
        } else if (a instanceof Dog){
            Dog d = (Dog)a;       
            d.watchHouse();       // 調用的是 Dog 的 watchHouse
        }
    }  
}

6、interface作爲參數傳遞

當接口作爲方法的參數時,需要傳遞它的子類對象。

  • 接口作爲參數時,傳遞它的子類對象。
  • 接口作爲返回值類型時,返回它的子類對象。

定義方法:

public static void printEvenNum(List list) {
    // 遍歷集合list
    for (int i = 0; i < list.size(); i++) {
        Object num = list.get(i);
        System.out.println(num);
    }
}

調用方法:

public class Test {
    public static void main(String[] args) {
        // 創建ArrayList集合,並添加數字
        ArrayList<Integer> srcList = new ArrayList<>();
        srcList.add(10);
		//調用方法,傳遞參數
        printEvenNum(srcList);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章