多態的引出
【多態的體現】 父類的引用或者接口的引用指向自己的子類對象。
Dog d=new Dog();
Animal a=new Dog();
【多態的好處】 提高了程序的擴展性。
【多態的弊端】 通過父類引用操作子類對象時,只能使用父類中已有的方法,不能操作子類持有的方法。
【多態的前提】 1. 必須有關係:繼承或實現。
2. 通常都有重寫操作。
【在多態的情況下調用子類的特有方法】
Animal a=new Dog();
Animal 是父類型,new Dog()是子類型。但是父類型引用指向子類對象時,這就是讓子類對象進行類型的提升(向上轉型)。
向上轉型的的好處:提高了擴展性,隱藏了子類型;弊端:不能使用子類型的特有方法。
如果要想使用子類的特有方法,可以向下轉型(強制轉換):
Animal a=new Dog();
a.eat()//這是Animal的方法,可以直接這樣用
Dog d=(Dog)a;//將a轉型爲Dog類型,向下轉型
d.lookHome();
當需要使用子類型的特有內容時使用向下轉型。
注意:無論向上還是向下轉型,最終都是子類對象做着類型的轉換。
【向下轉型的注意實項】
Animal a=new Dog();
Cat c=(Cat)a;
像上面這個錯誤的例子說明向下轉型不明確具體子類對象類型,所以容易引發ClassCastException異常。所以爲了避免這個問題,需要在向下轉型前判斷類型。
判斷類型的關鍵字爲:instanceof。
abstract public class Animal {
abstract void eat();
}
public class Cat extends Animal{
public void eat()
{
System.out.println("魚");
}
public void speak()
{
System.out.println("miaomiao");
}
}
public class Dog extends Animal {
public void eat()
{
System.out.println("骨頭");
}
public void speak()
{
System.out.println("wangwang");
}
}
public class Test {
public static void main(String[] args) {
Animal a1=new Dog();
method(a1);
Animal a2=new Cat();
method(a2);
}
public static void method(Animal A)
{
if(A instanceof Cat)
{
Cat c=(Cat)A;
c.eat();
}
else if(A instanceof Dog)
{
Dog d=(Dog)A;
d.eat();
}
}
}
結果:骨頭
魚
【轉型的總結】
1.問題:什麼時候向上轉型?
答案:不關係子類型。不需要子類的特有方法。
2. 問題:什麼時候向下轉型?
答案:需要使用子類型的特有方法時,但是一定要使用instanceof進行類型的判斷,避免ClassCastException。
【練習】(見https://blog.csdn.net/weixin_43677405/article/details/104098204)
【多態的成員調用的特點】
1. 成員變量
當子父類中出現同名的成員變量時,多態調用該變量時,
編譯時期,參考的是引用型變量所屬的類中是否有被調用的成員變量。如果沒有該變量就編譯失敗。
運算時期,也是調用引用型變量所屬的類中的成員變量。
簡單記:編譯和運都參考等號的左邊。
就比如下面這個例子:
public class Fu {
int num=3;
}
public class zi extends Fu{
int num=9;
}
public class DuoTaiDemo {
public static void main(String[] args) {
Fu f=new zi();
zi z=new zi();
System.out.println(f.num);
System.out.println(z.num);
}
}
結果:3
9
2. 成員函數(對於成員函數是動態綁定到對象上)
編譯:參考左邊,如果沒有,編譯失敗。
運行:參考等號右邊的類。
簡單記:編譯看左,運行看右。
public class Fu {
void show()
{
System.out.println("Fu show");
}
}
public class zi extends Fu{
void show()
{
System.out.println("zi show");
}
}
public class DuoTaiDemo {
public static void main(String[] args) {
Fu f=new zi();
zi z=new zi();
f.show();
z.show();
}
}
3. 靜態函數(靜態函數是靜態綁定到類上)
編譯和運行看左邊。
(真正的開發時靜態方法是不會被多態調用的,因爲靜態方法不屬於對象,而是所屬於類的。)
public class Fu {
static void show()
{
System.out.println("Fu static show");
}
}
public class zi extends Fu{
static void show()
{
System.out.println("zi static show");
}
}
public class DuoTaiDemo {
public static void main(String[] args) {
Fu f=new zi();
zi z=new zi();
f.show();
z.show();
}
}
結果:Fu static show
zi static show
【結論】
對於成員變量和靜態函數,編譯和運行都看左邊。
對於成員函數,編譯看左邊,運行看右邊。