Java的多態性

Java面向對象的三大特性:封裝(Encapsulation), 繼承(Inheritance), 多態(Polymorphism) 。
多態:同一個對象 體現出來的多種不同形態(身份) , 將一種行爲表現出不同的效果。
實現多態的效果的前提: 需要先有繼承關係。
我們先來看看代碼:
Animal 類,它默認繼承的是Object類:

public class Animal {

    public String name = "Animal的name屬性";

    public void eat(){
        System.out.println("animal的吃飯方法");
    }
    public void sleep(){
        System.out.println("animal的睡覺方法");
    }
}

繼承Animal類的Person類

public class Person extends Animal{

    public String name = "person的name屬性";

    public void eat(){
        System.out.println("person的吃飯方法");
    }
    public void sleep(){
        System.out.println("person的睡覺方法");
    }
    public void talk(){
        System.out.println("person的說話方法");
    }
}

繼承Animal類的Pig 類

public class Pig extends Animal{

    public String name = "pig的name屬性";

    public void sleep(){
        System.out.println("pig的睡覺方法");
    }
}

繼承Person類的Student 類

public class Student extends Person {

    public String name = "student的name屬性";

    public void talk(){
        System.out.println("學生遵守禮貌 應該好好說話");
    }
    public void study(){
        System.out.println("好好學習 天天向上");
    }
}

繼承Person類的Teacher 類

public class Teacher extends Person{

    public String name = "teacher的name屬性";
    public void eat(){
        System.out.println("做老師的通常不按時吃飯");
    }

    public void teach(){
        System.out.println("做老師的獨有方法 一般人不會講課 我會");
    }
}

我們先簡單梳理一下類關係:
在這裏插入圖片描述

測試:

Object o = new Teacher();//自動向上轉型,Teacher-->Object
o.hashCode();
o.toString();

以上代碼將父類(Object)類型的引用 指向 子類(Teacher)的對象,雖然o實際上是一個Teacher對象,但是它現在充當的是Object的角色,它只能調用到Object類下的所有方法。但是,執行hashCode()方法時,先要看該對象的真實類(Teacher)是否重寫該hashCode()方法,如果重寫,調用的就是Teacher類重寫的那個方法,如果沒有重寫,找Teacher類的上一級Person類,如果Person類重寫了該方法,就執行Person類重寫的那個方法,如果沒有沒有重寫,繼續找上一級Animal類,如此不斷向上找尋···,直到該方法被成功找到。
要注意的是,之所以可以向上轉型,前提是Teacher類是Object類的子類或者是Object類的子類的子類,必須具備直接或間接的繼承關係。

Animal a = (Animal)o;//強制向下轉型,Object--->Animal
a.hashCode();
a.toString();
System.out.println(a.name);//屬性沒有重寫一說,animal的name屬性
a.sleep();//從真實的類對象Teacher出發,Teacher沒有重寫  但person重寫了,執行person的sleep
a.eat();//執行teacher的eat方法

在這裏插入圖片描述

Person p = (Person)o;//強制向下轉型,Object--->Person
p.hashCode();
System.out.println(p.name);//person的name屬性
p.sleep();//人類的睡覺
p.eat();//老師的吃飯
p.talk();//人類的說話

在這裏插入圖片描述

Teacher t = (Teacher)o;//強制向下轉型,Object--->Teacher
System.out.println(t.name);//老師的name
t.eat();//老師的吃飯
t.sleep();//人類睡覺
t.talk();//人類說話
t.teach();//老師的獨有方法

在這裏插入圖片描述


以上代碼中,老師類和學生類都繼承自Person類,它們是平級關係,沒有繼承關係,那麼將teacher對象強制造型(鑄型)成student對象會怎樣呢?

Object o = new Teacher();
Student s = (Student)o;

這行代碼編譯好使,但是運行報錯,它是運行時異常:java.lang.ClassCastException
cast意爲鑄造,鑄型,它表示的是類鑄型異常,不能將Teacher 類對象鑄型爲Student對象:Teacher cannot be cast to Student。
我們如何有效避免鑄型時的異常呢?當我們不確定該類是否可以鑄型爲另一個類時,我們最好在前面加一個判斷:

   if(o instanceof Student){//對象是否屬於後面類型
       System.out.println("類型匹配  可以造型");
       Student s = (Student)o;//運行時異常 ClassCastException
       s.study();
   }else{
       System.out.println("對不起 類型不匹配 不幫您造型啦 否則會出問題");
   }

instanceof嚴格意義來講應該算作是一個運算符,運算的結果是true或false,它用來判斷一個對象是否屬於某一個類。

總結

多態的5個體現:

  1. 父類類型的引用 指向子類的對象
    Person p = new Teacher();
  2. 該引用只能調用父類中定義的屬性或方法
  3. 如果子類中將父類的方法重寫,那麼調取方法後執行的結果是子類重寫之後的那個結果
    如果父類與子類有同名的屬性 執行父類的屬性
    如果父類與子類有同名的方法(重寫) 執行子類重寫之後的方法
  4. 若想要調用子類中獨有的成員
    (強制類型轉化) 造型 鑄型 (向上/向下轉型)
  5. 造型時(強制向下轉型時) 可能會出現一個運行時異常
    ClassCastException (造型/鑄型 異常)
    如果想要避免造型的異常 可以用instanceof關鍵字來進行判斷
    instanceof嚴格意義來講應該算作是一個運算符,運算的結果是true或false,它用來判斷一個對象是否屬於某一個類
    用法是:對象 instanceof 類

最後總結以下常見的運行時異常:
InputMismatchException 輸入類型不匹配
NumberFormateException 數字格式化異常 Integer.parseInt(“abc”)
ArrayIndexOutOfBoundsException 數組索引越界
NegativeArraySizeException 數組長度負數 int [] arr = new int[-2];
NullPointerException 空指針異常 Person p = null; p.hashCode();
ArithmeticException 算數異常 10/0
ClassCastException 造型異常 將對象的類型還原時 與真實類型不匹配

運行時錯誤:
StackOverflowError 棧內存溢出錯誤

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