物件導向-多型
多型(掌握)
(1)同一個物件在不同時刻體現出來的不同狀態。
(2)多型的前提:
A:有繼承或者實現關係。
B:有方法重寫。
C:有父類或者父介面引用指向子類物件。
多型的分類:
a:具體類多型
class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
b:抽象類多型
abstract class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
c:介面多型
interface Fu {}
class Zi implements Fu {}
Fu f = new Zi();
(3)多型中的成員訪問特點
A:成員變數
編譯看左邊,執行看左邊
B:構造方法
子類的構造都會預設訪問父類構造
C:成員方法
編譯看左邊,執行看右邊
D:靜態方法
編譯看左邊,執行看左邊
/*
多型:同一個物件(事物),在不同時刻體現出來的不同狀態。
舉例:
貓是貓,貓是動物。
水(液體,固體,氣態)。
多型的前提:
A:要有繼承關係。
B:要有方法重寫。
其實沒有也是可以的,但是如果沒有這個就沒有意義。
動物 d = new 貓();
d.show();
動物 d = new 狗();
d.show();
C:要有父類引用指向子類物件。
父 f = new 子();
用程式碼體現一下多型。
多型中的成員訪問特點:變數沒有重寫,用的還是父親的;因為方法有重寫,父類方法被子類覆蓋掉了,只留下子類的方法
A:成員變數
編譯看左邊,執行看左邊。
B:構造方法
建立子類物件的時候,訪問父類的構造方法,對父類的資料進行初始化。
C:成員方法
編譯看左邊,執行看右邊。
D:靜態方法
編譯看左邊,執行看左邊。
(靜態和類相關,算不上重寫,所以,訪問還是左邊的)
由於成員方法存在方法重寫,所以它執行看右邊。
*/
public class Fu {
public int num = 100;
public void show() {
System.out.println("show Fu");
}
public static void function() {
System.out.println("function Fu");
}
}
public class Zi extends Fu {
public int num = 1000;
public int num2 = 200;
public void show() {
System.out.println("show Zi");
}
public void method() {
System.out.println("method zi");
}
public static void function() {
System.out.println("function Zi");
}
}
public class DuoTaiDemo {
public static void main(String[] args) {
//要有父類引用指向子類物件。
//父 f = new 子();
Fu f = new Zi();
System.out.println(f.num); //100
//System.out.println(f.num2);//報錯:找不到符號
f.show(); //show Zi
//f.method(); //報錯:找不到符號
f.function(); //function Fu
}
}
(4)多型的好處:
A:提高程式碼的維護性(繼承體現)
B:提高程式碼的擴充套件性(多型體現)
/*
多型的好處:
A:提高了程式碼的維護性(繼承保證)
B:提高了程式碼的擴充套件性(由多型保證)
貓狗案例程式碼
*/
class Animal {
public void eat(){
System.out.println("eat");
}
public void sleep(){
System.out.println("sleep");
}
}
class Dog extends Animal {
public void eat(){
System.out.println("狗吃肉");
}
public void sleep(){
System.out.println("狗站著睡覺");
}
}
class Cat extends Animal {
public void eat() {
System.out.println("貓吃魚");
}
public void sleep() {
System.out.println("貓趴著睡覺");
}
}
class Pig extends Animal {
public void eat() {
System.out.println("豬吃白菜");
}
public void sleep() {
System.out.println("豬側著睡");
}
}
//針對動物操作的工具類
class AnimalTool {
private AnimalTool(){}
/*
//呼叫貓的功能
public static void useCat(Cat c) {
c.eat();
c.sleep();
}
//呼叫狗的功能
public static void useDog(Dog d) {
d.eat();
d.sleep();
}
//呼叫豬的功能
public static void usePig(Pig p) {
p.eat();
p.sleep();
}
*/
public static void useAnimal(Animal a) {
a.eat();
a.sleep();
}
}
class DuoTaiDemo2 {
public static void main(String[] args) {
//我喜歡貓,就養了一隻
Cat c = new Cat();
c.eat();
c.sleep();
//我很喜歡貓,所以,又養了一隻
Cat c2 = new Cat();
c2.eat();
c2.sleep();
//我特別喜歡貓,又養了一隻
Cat c3 = new Cat();
c3.eat();
c3.sleep();
//...
System.out.println("--------------");
/*
問題來了,我養了很多隻貓,每次建立物件是可以接受的
但是呢?呼叫方法,你不覺得很相似嗎?僅僅是物件名不一樣。
我們準備改進
*/
//useCat(c);
//useCat(c2);
//useCat(c3);
//AnimalTool.useCat(c);
//AnimalTool.useCat(c2);
//AnimalTool.useCat(c3);
AnimalTool.useAnimal(c);
AnimalTool.useAnimal(c2);
AnimalTool.useAnimal(c3);
System.out.println("--------------");
//我喜歡狗
Dog d = new Dog();
Dog d2 = new Dog();
Dog d3 = new Dog();
//AnimalTool.useDog(d);
//AnimalTool.useDog(d2);
//AnimalTool.useDog(d3);
AnimalTool.useAnimal(d);
AnimalTool.useAnimal(d2);
AnimalTool.useAnimal(d3);
System.out.println("--------------");
//我喜歡寵物豬
//定義一個豬類,它要繼承自動物,提供兩個方法,並且還得在工具類中新增該類方法呼叫
Pig p = new Pig();
Pig p2 = new Pig();
Pig p3 = new Pig();
//AnimalTool.usePig(p);
//AnimalTool.usePig(p2);
//AnimalTool.usePig(p3);
AnimalTool.useAnimal(p);
AnimalTool.useAnimal(p2);
AnimalTool.useAnimal(p3);
System.out.println("--------------");
/*
我喜歡寵物狼,老虎,豹子...
定義對應的類,繼承自動物,提供對應的方法重寫,並在工具類新增方法呼叫
前面幾個必須寫,我是沒有意見的
但是,工具類每次都改,麻煩不
我就想,你能不能不改了
太簡單:把所有的動物都寫上。問題是名字是什麼呢?到底哪些需要被加入呢?
改用另一種解決方案。
public static void useAnimal(Animal a) {
a.eat();
a.sleep();
}
*/
}
}
(5)多型的弊端:
父不能使用子的特有功能。
現象:
子可以當作父使用,父不能當作子使用。
/*
多型的弊端:
不能使用子類的特有功能。
*/
class Fu {
public void show() {
System.out.println("show fu");
}
}
class Zi extends Fu {
public void show() {
System.out.println("show zi");
}
public void method() {
System.out.println("method zi");
}
}
class DuoTaiDemo3 {
public static void main(String[] args) {
//測試
Fu f = new Zi();
f.show(); //show zi
f.method();//報錯:方法未定義
}
}
(6)多型中的轉型
A:向上轉型
從子到父,父類引用指向子類物件:Fu f = new Zi();
B:向下轉型
從父到子,父類引用轉為子類物件:Zi z = (Zi)f;
/*
多型的弊端:
不能使用子類的特有功能。
我就想使用子類的特有功能?行不行?
行。
怎麼用呢?
A:建立子類物件呼叫方法即可。(可以,但是很多時候不合理。而且,太佔記憶體了)
B:把父類的引用強制轉換為子類的引用。(向下轉型)
物件間的轉型問題:
向上轉型:
Fu f = new Zi();
向下轉型:
Zi z = (Zi)f; //要求該f必須是能夠轉換為Zi的。
*/
class Fu {
public void show() {
System.out.println("show fu");
}
}
class Zi extends Fu {
public void show() {
System.out.println("show zi");
}
public void method() {
System.out.println("method zi");
}
}
class DuoTaiDemo4 {
public static void main(String[] args) {
//測試
Fu f = new Zi();
f.show(); //show zi
//f.method();//報錯:方法未定義
//建立子類物件,可以,但是很多時候不合理。而且,太佔記憶體了。
//Zi z = new Zi();
//z.show();
//z.method();
//你能夠把子的物件賦值給父親,那麼我能不能把父的引用賦值給子的引用呢?
//如果可以,程式碼如下:
//向下轉型
Zi z = (Zi)f;
z.show(); //show zi
z.method();//method zi
}
}
(7)孔子裝爹的案例幫助大家理解多型
多型的問題理解:
class 孔子爹 {
public int age = 40;
public void teach() {
System.out.println("講解JavaSE");
}
}
class 孔子 extends 孔子爹 {
public int age = 20;
public void teach() {
System.out.println("講解論語");
}
public void playGame() {
System.out.println("英雄聯盟");
}
}
//Java培訓特別火,很多人來請孔子爹去講課,這一天孔子爹被請走了
//但是還有人來請,就剩孔子在家,價格還挺高。孔子一想,我是不是可以考慮去呢?
//然後就穿上爹的衣服,帶上爹的眼睛,粘上爹的鬍子。就開始裝爹
//向上轉型
孔子爹 k爹 = new 孔子();
//到人家那裡去了
System.out.println(k爹.age); //40
System.out.println(k爹.teach()); //講解論語
//k爹.playGame(); //這不行,這是兒子才能做的
//講完了,下班回家了,脫下爹的裝備,換上自己的裝備
//向下轉型
孔子 k = (孔子) k爹;
System.out.println(k.age); //20
k.teach(); //講解論語
k.playGame(); //英雄聯盟
補充:多型繼承中的記憶體圖解
補充:一般在多型的向下轉型中容易出現ClassCastException:型別轉換異常
/*
ClassCastException:型別轉換異常
一般在多型的向下轉型中容易出現
*/
class Animal {
public void eat(){}
}
class Dog extends Animal {
public void eat() {}
public void lookDoor() {
}
}
class Cat extends Animal {
public void eat() {
}
public void playGame() {
}
}
class DuoTaiDemo5 {
public static void main(String[] args) {
//記憶體中的是狗
Animal a = new Dog();
Dog d = (Dog)a;
//記憶體中是貓
a = new Cat();
Cat c = (Cat)a;
//記憶體中是貓
Dog dd = (Dog)a; //ClassCastException
}
}
(8)多型的練習
/*
多型練習:貓狗案例
*/
class Animal {
public void eat(){
System.out.println("吃飯");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("狗吃肉");
}
public void lookDoor() {
System.out.println("狗看門");
}
}
class Cat extends Animal {
public void eat() {
System.out.println("貓吃魚");
}
public void playGame() {
System.out.println("貓捉迷藏");
}
}
class DuoTaiTest {
public static void main(String[] args) {
//定義為狗
Animal a = new Dog();
a.eat();//狗吃肉
//還原成狗
Dog d = (Dog)a;
d.eat(); //狗吃肉
d.lookDoor();//狗看門
//變成貓
a = new Cat();
a.eat();//貓吃魚
//還原成貓
Cat c = (Cat)a;
c.eat(); //貓吃魚
c.playGame();//貓捉迷藏
//演示錯誤的內容
//Dog dd = new Animal();//不相容的型別
//Dog ddd = new Cat(); //不相容的型別
//Dog dd = (Dog)a; //ClassCastException
}
}
/*
不同地方飲食文化不同的案例
*/
class Person {
public void eat() {
System.out.println("吃飯");
}
}
class SouthPerson extends Person {
public void eat() {
System.out.println("炒菜,吃米飯");
}
public void jingShang() {
System.out.println("經商");
}
}
class NorthPerson extends Person {
public void eat() {
System.out.println("燉菜,吃饅頭");
}
public void yanJiu() {
System.out.println("研究");
}
}
class DuoTaiTest2 {
public static void main(String[] args) {
//測試
//南方人
Person p = new SouthPerson();
p.eat(); //炒菜,吃米飯
SouthPerson sp = (SouthPerson)p;
sp.eat(); //炒菜,吃米飯
sp.jingShang(); //經商
//北方人
p = new NorthPerson();
p.eat(); //燉菜,吃饅頭
NorthPerson np = (NorthPerson)p;
np.eat(); //燉菜,吃饅頭
np.yanJiu(); //研究
}
}
看程式寫結果:
/*
看程式寫結果:先判斷有沒有問題,如果沒有,寫出結果
多型的成員訪問特點:
方法:編譯看左邊,執行看右邊。
繼承的時候:
子類中有和父類中一樣的方法,叫重寫。
子類中沒有父親中出現過的方法,方法就被繼承過來了。
*/
class A {
public void show() {
show2();
}
public void show2() {
System.out.println("我");
}
}
class B extends A {
/*可以理解存在該程式碼,因為繼承了父類的方法
public void show() {
show2();
}
*/
public void show2() {
System.out.println("愛");
}
}
class C extends B {
public void show() {
super.show();
}
public void show2() {
System.out.println("你");
}
}
public class DuoTaiTest4 {
public static void main(String[] args) {
A a = new B();
a.show(); //愛
B b = new C();
b.show(); //你
}
}
相關文章
- Java物件導向--多型Java物件多型
- 物件導向:封裝,多型物件封裝多型
- Java物件導向總結(多型)Java物件多型
- Java007-物件導向(多型)Java物件多型
- [.net 物件導向程式設計基礎] (13) 物件導向三大特性——多型物件程式設計多型
- [譯] part 28: golang 的物件導向 -- 多型Golang物件多型
- java-物件導向程式設計--多型Java物件程式設計多型
- JAVA高階物件導向二:認識多型 多型的好處Java物件多型
- JAVA物件導向之多型Java物件多型
- 物件導向三大特性-----封裝、繼承、多型物件封裝繼承多型
- 物件導向三大特徵(封裝/繼承/多型)物件特徵封裝繼承多型
- 物件導向基礎(1)--繼承 多型 重構物件繼承多型
- JAVA物件導向基礎--封裝 繼承 多型Java物件封裝繼承多型
- JS物件導向Object型別JS物件Object型別
- 22. 物件導向之多型物件多型
- 物件導向-物件導向思想物件
- 物件導向 -- 三大特性之多型物件多型
- 物件導向-設計模式-建立型物件設計模式
- [JAVA] Java物件導向三大特徵:封裝、繼承、多型Java物件特徵封裝繼承多型
- Java第八課. 物件導向特徵3-多型&抽象類Java物件特徵多型抽象
- 理解C++物件導向程式設計[多型性部分] (轉)C++物件程式設計多型
- 物件導向的三個基本特徵是:封裝、繼承、多型物件特徵封裝繼承多型
- Python物件導向多型實現原理及程式碼例項Python物件多型
- 物件導向-設計模式-行為型物件設計模式
- 物件導向-設計模式-結構型物件設計模式
- 物件導向--內部屬性型別物件型別
- php物件導向多繼承實現PHP物件繼承
- 程式導向與物件導向物件
- 物件導向與程式導向物件
- “程序導向”和“物件導向”物件
- 物件導向物件
- java核心思想物件導向三大特性(封裝,繼承,多型)Java物件封裝繼承多型
- Java 重寫和過載區別——物件導向的多型性分析Java物件多型
- 26. 企業級開發基礎7:物件導向特徵(多型)物件特徵多型
- 物件導向,搞定物件物件
- PHP 物件導向 (九)物件導向三大特徵PHP物件特徵
- JAVA物件導向基礎--物件導向介紹Java物件
- JavaScript物件導向程式設計——Array型別JavaScript物件程式設計型別