一、多態 定義:指允許不同子類的對象對父類同一消息能做出不同的響應。(重寫父類的方法) 即同一消息可以根據發送對象的不同而採用多種不同的行為方式。(發送消息就是函數調用) 1、面向對象的多態的實現前提: (1)要有繼承:類與類之間必須有繼承關係; (2)要有重寫:子類重寫父類的成員方法(可以不重寫, ...
一、多態
理解:多態本意是指同一事物在不同的條件會有不同的形態;
映射到Java中可以理解為:同一個父類方法被不同的子類調用,會產生不同的行為(重寫父類的方法);
也可表述為:不同子類的對象對父類同一消息能做出不同的響應(重寫父類的方法)。 即同一消息可以根據發送對象的不同而採用多種不同的行為方式(發送消息就是函數調用)。
1、面向對象的多態的實現前提:
(1)要有繼承:類與類之間必須有繼承關係;
(2)要有重寫:子類重寫父類的成員方法(可以不重寫,但這就失去了多態的意義);
(3)向上轉型:父類引用可以指向任何一個子類的對象。
2、向上轉型(子類自動轉為父類):子類"偽裝"成父類,執行子類的方法;
class Fu {
.....
}
class Zi extends Fu {
.....
}
Fu fu = new Zi();
父類 父類引用 = 子類對象
註:
1、Java指向的兩個時期:編譯器與執行器,編譯期看類型,執行期看對象。
2、多態調用函數的處理過程: 編譯器從父類查找是否有該函數,沒有的話報錯,有的話在執行期執行子類中重寫的同名函數,而不是父類。
常式:duotai包:ZMS.java ZMSSON.java
3、向下轉型(父類強制轉化為子類):"偽裝"成父類的"子類"還原成真正的子類
Zi zi = (Zi) fu; //類似於強制轉換大範圍到小範圍
常式:duotai包:ZMS.java ZMSSON.java
ZMS.java
1 package duoTai; 2 3 public class ZMS { 4 String name; 5 int age; 6 7 public void teach() { 8 9 System.out.println("我是父類ZMS教Java"); 10 } 11 12 public void show() { 13 System.out.println(name+age); 14 15 } 16 17 }View Code
ZMSSON.java
1 package duoTai; 2 /** 3 * 創建ZMS子類 4 * 多態的測試 5 * 6 * */ 7 public class ZMSSON extends ZMS { 8 9 //重寫父類中同名方法 10 public void teach() { 11 12 System.out.println("我是ZMS子類教文學"); 13 // like(); 14 } 15 16 //子類自己的成員方法 17 public void like() { 18 System.out.println("ZMSSON喜歡踢球"); 19 20 } 21 22 public static void main(String[] args) { 23 24 /* 25 * 多態的表示:父類 父類引用名 = 子類對象 26 * 多態調用函數的處理過程: 編譯器從父類查找是否有該函數,沒有的話報錯, 27 * 有的話在執行期執行子類中重寫的同名函數,而不是父類。 28 * 29 * */ 30 ZMS zmsText = new ZMSSON(); 31 zmsText.teach(); 32 33 //調用不了父類沒有的方法 34 //zmsText.like(); 35 36 //調用父類的成員變數方法 37 zmsText.name = "zms"; 38 zmsText.age = 65; 39 zmsText.show(); 40 41 // 42 ZMSSON zmsSon = (ZMSSON) zmsText; 43 zmsSon.teach(); 44 zmsSon.like(); 45 46 } 47 48 }View Code
4、多態的好處:
(1)提高了代碼的復用性(繼承)
(2)提高了代碼的擴展性(多態)
5、instanceof 關鍵字:
boolean b = a instanceof b;
判斷a類是否屬於另一個b類,是返回true,否則返回false。
練習:跟據從鍵盤輸入數字不同選擇不同的子類對象,執行不同的響應(重點理解);
常式:duotai包:Animal.java duoTaiAnimal.java
創建父類:
1 package duoTai; 2 3 public class Animal { 4 public String name ; 5 public int age; 6 7 public void eat() { 8 System.out.println(name+"動物吃東西"); 9 } 10 11 }View Code
創建兩個子類:
1 package duoTai; 2 3 public class Cat extends Animal{ 4 5 //重寫父類方法 6 public void eat() { 7 System.out.println("貓吃魚"); 8 9 } 10 11 //寫子類自己的方法 12 public void catchMouse() { 13 System.out.println("抓老鼠"); 14 } 15 16 } 17 18 19 // 在另一個java文件中創建 20 package duoTai; 21 22 public class Dog extends Animal{ 23 24 //重寫父類方法 25 public void eat() { 26 System.out.println("吃狗糧"); 27 } 28 29 //寫子類自己的方法 30 public void kanMen() { 31 System.out.println("狗看門"); 32 } 33 }View Code
創建測試功能類:
1 package duoTai; 2 3 /** 4 * @author Kanekiyi 5 * 理解多態的意義:同一消息(函數)可以根據發出的對象不同而產生不同的行為方式。 6 * Or 不同的對象調用同一個函數能夠產生不同的行為方式。 7 */ 8 import java.util.Scanner; 9 10 public class duoTaiAnimal { 11 12 @SuppressWarnings("resource") 13 public static void main(String[] args) { 14 15 System.out.println("請輸入數字1選擇貓,數字2選擇狗"); 16 Scanner sc = new Scanner(System.in); 17 18 int num = sc.nextInt(); 19 Animal animal = new Animal(); 20 /* 21 * 向上轉型時,根據指令選擇不同的對象源 22 */ 23 if (num == 1) { 24 animal = new Cat(); 25 } else if (num == 2) { 26 animal = new Dog(); 27 } else { 28 System.out.println("輸入數字錯誤請重新輸入數字1或者2"); 29 } 30 31 runAnimal ( animal); 32 33 } 34 35 public static void runAnimal(Animal a) { 36 37 //根據對象的不同執行子類重寫的eat()方法; 38 a.eat(); 39 40 /* 41 * 向下轉型時,註意轉型目標子類類型是否符合 42 * 目的:執行子類中特有的功能 43 * 44 */ 45 46 if (a instanceof Cat) { 47 Cat cat = (Cat) a; 48 cat.catchMouse(); 49 50 } else if (a instanceof Dog) { 51 Dog dog = (Dog) a; 52 dog.kanMen(); 53 54 } else { 55 System.out.println("輸入錯誤,不屬於cat類也不屬於Dog類"); 56 } 57 58 } 59 60 }View Code
二、final 關鍵字
2.1 final修飾類
final修飾的類不能被繼承;
2.2 final修飾變數
final 變數能被顯式地初始化並且只能初始化一次。被聲明為 final 的對象的引用不能指向不同的對象,但是 final 對象里的數據可以被改變。也就是說 final 對象的引用不能改變,但是裡面的值可以改變。(存疑)。
final與static一起修飾成員變數構成常量,聲明的時候常量名全部大寫,可以直接通過類名訪問。
常式:
1 package Fianal; 2 3 4 //public class Final1 extends Final0{ final修飾的類不能夠被繼承 5 public class Final1 { 6 7 int IDCard ; 8 //final修飾的成員變數聲明時初始化且有且只初始化一次。 9 final int IDCardNum =314; 10 final int IDCardNum1; 11 12 static final String IDCARD= "36452345245X"; 13 14 //通過構造函數給final修飾的成員變數初始化 15 public Final1() { 16 super(); 17 IDCardNum1 =314; 18 19 } 20 21 public final void textMath() { 22 23 System.out.println("我是Final1類的final方法"); 24 } 25 26 27 }View Code
2.3 final 修飾方法
final 修飾成員方法,可以被子類繼承,但是不能被重寫;
註:
1、final 修飾的成員變數初始化的兩種方式:
(1) 聲明時就初始化;
(2)通過構造函數初始化。
且只初始化一次,初始化後就不能修改。
2、final 修飾的變數為常量時,在載入時系統會將變數替換為其所表示的常量。
常式:
1 package Fianal; 2 3 public class Final2 extends Final1 { 4 5 //父類final修飾的成員方法不能重寫,只能調用 6 //public final void textMath() {} 7 8 public static void main(String[] args) { 9 Final2 textFinal = new Final2(); 10 textFinal.IDCard = 2; 11 12 //final修飾的變數在聲明時就初始化且只能初始化一次,只能被調用不能被修改 13 //textFinal.IDCardNum = 3; 14 System.out.println("普通成員變數IDCard:"+textFinal.IDCard); 15 System.out.println("final修飾的成員變數IDCardNum:"+textFinal.IDCardNum); 16 //System.out.println("final和static修飾的成員變數IDCARD:"+textFinal.IDCARD); 17 //常量可以直接調用或類名調用 18 System.out.println("final和static修飾的成員變數IDCARD:"+Final1.IDCARD); 19 System.out.println("final和static修飾的成員變數IDCARD:"+IDCARD); 20 21 textFinal.textMath(); 22 23 } 24 25 }View Code