Java入門姿勢【面向物件9】三大特性之一多型性
上次我為大家寫出啦“繼承性”中比較重要的知識點,同時也結束繼承性這一章節的話題,今天吶我們來講解一下另一個知識點“多型性”,多型性是面向物件三大特性之一是Java學習必備的知識。
學習教程推薦:
- 1.北京高淇Java300集(Java強烈推薦)
Java300集零基礎適合初學者視訊教程_Java300集零基礎教程_Java初學入門視訊基礎鞏固教程_Java語言入門到精通 - 2.JavaSE基礎全套-從零開始進階之大神(推薦)
系統教學JavaSE基礎全套課程-從0開始進階至大神_線下錄製Java系列課程Java從入門到精通_/JAVA基礎/陣列/OOP/集合/IO流_ - 3.Java常用類基礎實戰
【基礎夯實】Java常用類實戰基礎教程_Java八大常用類核心基礎_Java常用類基礎入門/Java包裝類/String類 - 4.Java基礎入門必備數學知識【資料結構與演算法】(推薦)
Java基礎入門必學知識資料結構與演算法_Java資料結構與演算法基礎到進階/Java基礎入門進階/Java資料結構分析/Java資料結構常見問題_嗶哩嗶哩_bilibili - 5.Java面向物件程式設計_OOP基礎深入講解
Java面向物件程式設計重基礎深入講解_OOP面向物件Java基礎乾貨分享/JavaSE/面向物件程式設計/OOP程式設計 - 6.GOF23種設計模式-23中設計模式詳解課程
GOF23種設計模式講解_Java gof23種設計模式詳解課程_從單例到備忘錄模式 23種模式詳解
多型(polymorphism)是面向物件三大特徵之一。同一行為,通過不同的子類,可以體現出來的不同的形態。
多型指的是同一個方法呼叫,由於物件不同可能會有不同的行為。現實生活中,同一個方法,具體實現會完全不同。 比如:同樣是呼叫人的“休息”方法,張三是睡覺,李四是旅遊,王五是聽音樂; 同樣是呼叫人“吃飯”的方法,中國人用筷子吃飯,英國人用刀叉吃飯,印度人用手吃飯。
編譯器型別指的是‘=’左邊的型別,執行期型別指的是‘=’右邊的型別。當有繼承關係時,可能發生編譯期型別和執行期型別不同的情況,即編譯期型別是父類型別,執行期型別是子類型別。即:父類引用指向子類物件
多型的要點:
1. 多型是方法的多型,不是屬性的多型(多型與屬性無關)。
2. 多型的存在要有3個必要條件:繼承,方法重寫,父類引用指向子類物件。
3. 父類引用指向子類物件後,用該父類引用呼叫子類重寫的方法,此時多型就出現了。
編寫程式碼,為多型做準備:
public class Programmer {
public String name ="proName";//姓名
//1.子類繼承的
public void writeCode(){
System.out.println("writing code............");
}
//2.子類重寫的
public void eat(){
System.out.println("eating with mouse.............");
}
}
public class Chinese extends Programmer{
public String name = "ChinName";
//1.從父類繼承一個方法 writeCode()
//2.重寫父類的一個方法 eat
public void eat() {
System.out.println(" Chinese eat rice with chopsticks.....");
}
//3.子類特有的方法
public void playShadowBoxing(){
System.out.println("Chinese play showdowBoxing every day......");
}
}
public class English extends Programmer {
//1.從父類繼承一個方法 writeCode()
//2.重寫父類的一個方法 eat
public void eat() {
System.out.println("English eating meat with knife.....");
}
//3.子類特有的方法
public void raceHorse(){
System.out.println("English like racing horse......");
}
}
public class Italian extends Programmer {
//1.從父類繼承一個方法 writeCode()
//2.重寫父類的一個方法 eat
public void eat() {
System.out.println("Italian eating pizza with hand......");
}
//3.子類特有的方法
public void playFootBall(){
System.out.println("Italian like play football.....");
}
}
實現eat()多型
public class Test {
// public static void showEat(Chinese ch){
// ch.eat();
// }
// public static void showEat(Italian it){
// it.eat();
// }
// public static void showEat(English en){
// en.eat();
// }
public static void showEat(Programmer pro){
pro.eat();
}
public static void main(String[] args) {
//Chinese ch = new Chinese();
Programmer ch = new Chinese();
showEat(ch);
English en = new English();
showEat(en);
Italian it = new Italian();
showEat(it);
Programmer pro = new Programmer();
showEat(pro);
}
}
public class Test2 {
public static void main(String[] args) {
Chinese ch = new Chinese();
ch.writeCode();//從父類繼承的
ch.eat();//重寫父類的
ch.playShadowBoxing();//子類特有的方法
Programmer ch2 = new Chinese();
ch2.writeCode(); //非多型
ch2.eat(); // 多型 呼叫的是子類重寫的方法
//ch2.playShadowBoxing(); // 無法呼叫子類特有的方法
}
}
使用父類做方法的形參,是多型使用最多的場合。即使增加了新的子類,方法也無需改變,符合開閉原則。
父類引用做方法的形參,實參可以是任意的子類物件,可以通過不同的子類物件實現不同的行為方式。另外即使增加了新的子類,方法也無需改變,提高了擴充套件性,符合開閉原則。
多型之向上轉型
將子類物件賦給父類引用,稱為向上轉型(upcasting),自動進行型別轉換。
向上轉型可以呼叫的子類繼承的方法,但不能呼叫子類特有的方法。需要特別理解的是如果子類重寫了父類的方法,向上轉型後通過父類引用呼叫的卻是真實子類重寫的方法,
向上轉型-程式碼示例:
public class TestPoly {
public static void main(String[] args) {
//基本資料型別的自動轉換
int n = 10;
System.out.println( n );
double d = n; // 左>右 自動轉換
System.out.println(d);
//引用資料型別的自動轉換
Programmer programmer = new Chinese(); // 自動轉換 向上轉型 左>右
programmer.writeCode();
programmer.eat();
//programmer.playShadowBoxing();
}
}
如何理解向上轉型?
1) 招聘程式設計師,來個英國籍程式設計師,滿足要求,不需要特別宣告
2) 不管是哪個國籍的,寫到程式碼都是Java程式碼
3) 中午休息了,大家都去食堂開始吃飯,原形畢露
4) 老闆隨便找一個程式設計師,說一起賽馬吧,不可以;因為對方可能是中國或義大利程式設計師
多型之向下轉型
將父類的引用變數轉換為子類型別,稱為向下轉型(downcasting)。向下轉型後就可以呼叫子類特有的方法了。
- 需要進行強制轉換Chinese ch = (Chinese)pro;
- 強制轉換不是做手術,必須轉換成真實子型別,否則ClassCastException;
- 向下轉型之前肯定發生了向上轉型
- 為了避免ClassCastException,向下轉型之前使用instanceof先判斷一下
pro instanceof Italian
物件 instanceof 類或者介面
使用instancof的前提:左邊的物件和右邊的型別在繼承樹上有上下級關係
向下轉型-程式碼示例:
public class TestPoly2 {
public static void main(String[] args) {
//基本資料型別的強制轉換
double d = 3.14;
System.out.println(d);
int n = (int)d; // 左 < 右 做手術
System.out.println(n);
//引用資料型別的強制轉換
Programmer programmer = new Chinese();
programmer.eat();//多型
//programmer.playShadowBoxing();
// Chinese ch = (Chinese) programmer; // 左<右 不做手術,必須轉換成原來//的真實子型別
// ch.playShadowBoxing();//
// English en = (English)programmer;
// en.raceHorse();
if(programmer instanceof Chinese){
Chinese ch = (Chinese) programmer;
ch.playShadowBoxing();
}else if(programmer instanceof English){
English en = (English) programmer;
en.raceHorse();
}else{
Italian it = (Italian) programmer;
it.playFootBall();
}
//java.lang.ClassCastException:
// com.bjsxt.poly0.Chinese cannot be cast to com.bjsxt.poly0.English
System.out.println(programmer instanceof Chinese); //false
System.out.println(programmer instanceof English); //true
System.out.println(programmer instanceof Programmer);//true
System.out.println(programmer instanceof Object);//true
//System.out.println(programmer instanceof String);
}
}
需要注意的點:多型之和方法有關,和屬性無關。入下面示例所示。
多型和屬性無關-程式碼示例:
public class TestPoly3 {
public static void main(String[] args) {
Chinese chinese = new Chinese();
System.out.println(chinese.name);
Programmer programmer = new Programmer();
System.out.println(programmer.name);
Programmer programmer2 = new Chinese();
System.out.println(programmer2.name); //ChinName proName
programmer2.eat();
}
}
多型實現簡單工廠模式-返回值是父類型別
不僅可以使用父類做方法的形參,還可以使用父類做方法的返回值型別,真實返回的物件可以是該類的任意一個子類物件。
程式碼示例:
public class TestPoly4 {
public static void main(String[] args) {
//自己培養了一個程式設計師
//Programmer pro = new Chinese();
Programmer pro = SxtSchool.getProgrammer("en");
//讓程式設計師幹活
pro.writeCode();
}
}
class SxtSchool{
public static Programmer getProgrammer(String type){
Programmer pro = null;
if("ch".equals(type)){
pro = new Chinese();
}else if("en".equals(type)){
pro = new English();
}else{
pro = new Italian();
}
return pro;
}
}
以上程式碼其實是簡單工廠模式的實現,它是解決大量物件建立問題的一個解決方案。將建立和使用分開,工廠負責建立,使用者直接呼叫即可。簡單工廠模式的基本要求是
- 定義一個static方法,通過類名直接呼叫
- 返回值型別是父類型別,返回的可以是其任意子類型別
- 傳入一個字串型別的引數,工廠根據引數建立對應的子類產品