1.多態的定義
通俗來說,當同一種行為或者事情發生在不同的對象上,這些行為或者事情最終得到的結果不同。
注意:多態要發生在繼承的基礎上。
例如:彩色打印機和黑白打印機。
彩色打印機和黑白打印機是不同的對象,但打印(行為)這件事分別發生在它們身上的時候,彩色打印機打印的是彩色的,而黑白打印機最終打印的結果卻是黑白色的。
對應到Java中就是相同的方法對應到不同的對象中有不同的結果。
?2.多態的使用
2.1 向上轉型
向上轉型發生在繼承的基礎上,所謂向上轉型,就是由子類類型向父類類型轉換。向上轉型的方式由3中,分別為:直接賦值、方法的傳參和方法的返回值形式。
1.直接傳參
class Animal{}
class Dog extends Animal{}
public class Test {public static void main(String[] args) {//直接賦值,發生向上轉型Animal animal=new Dog();}
}
2. 方法的傳參
class Animal{}
class Dog extends Animal{}
public class Test {public static void func(Animal animal){}public static void main(String[] args) {Dog dog=new Dog();//方法的傳參實現向上轉型func(dog);}
}
3.方法的返回值
class Animal{}
class Dog extends Animal{}
public class Test {public static Animal func(){Dog dog=new Dog();return dog;}public static void main(String[] args) {Animal animal=func(); }
}
4 向上轉型的缺點
當我們進行了向上轉型,我們就不能通過父類的引用(轉型之后的引用)去訪問子類特有的屬性或者方法。?
class Dog extends Animal{public Dog(String name,int age){super(name, age);}public void bark(){System.out.println(this.name+"在汪汪叫");}
}
class Animal{public String name;public int age;public Animal(String name,int age){this.name=name;this.age=age;}
}
public class Test {public static void main(String[] args) {Animal animal=new Dog("旺財",18);animal.bark();}
}
運行以上代碼會報錯
?2.2 動態綁定
動態綁定是理解多態的基礎。
?1.方法的重寫
當子類和父類中有一個方法名字一樣,參數列表一樣和返回值類型一樣,但是方法內不得具體實現不一樣,則子類對應的方法構成了方法的重寫。
class Dog extends Animal{public Dog(String name,int age){super(name, age);}@Override //編譯器中方法重寫的默認注釋public void eat() {System.out.println(this.name+"在吃狗糧");}
}
class Animal{public String name;public int age;public Animal(String name,int age){this.name=name;this.age=age;}public void eat(){System.out.println(this.name+"在吃飯");}
}
public class Test {public static void main(String[] args) {Animal animal=new Dog("旺財",18);}
}
如上圖,紅框框里面就是構成重寫的部分。
2.方法重寫的注意事項
1.重寫的方法不能是一個靜態的方法(被static修飾的方法)。
2.被final修飾的方法無法被重寫
3.如果子類重寫父類的方法時,子類重寫方法時的訪問權限要大于等于父類方法的權限。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 訪問權限大小比較 |
? ? ? ? ? ? ? ? ? ? ? ? ? public>protected>default>private |
如圖,因為父類要被重寫的方法得訪問權限為public,而子類中重寫的方法的訪問權限為private,所以運行代碼時,編譯器會報錯。
4.父類中被private修飾的方法無法被重寫
5.重寫的方法的返回值類型可以不相同,但是返回值類型必須構成父子類的關系。
? ? ? ? ? ? ? ? ? ? ? ? ?
3. 方法的重寫和重載的區別
? ? ? ? ? ? ? ? ? ? ? ? ?重載 | ? ? ? ? ? ? ? ? ? ? ? 重寫 |
? ?參數列表中的數據類型,順序和個priv數可以不一樣 | ?參數列表中的數據類型,順序和個數必須一樣 |
? ?返回值的類型不一樣 | ? 返回值類型必須一樣 |
? ?方法名必須一樣 | ? ?方法名必須一樣 |
4.動態綁定
當運行代碼時,我們通過父類的引用去調用在子類和父類中重寫的方法,結果實際調用了子類的方法,這種情況就被稱為動態綁定。
?代碼演示
class Dog extends Animal{public Dog(String name,int age){super(name, age);}@Override //編譯器中方法重寫的默認注釋public void eat() {System.out.println(this.name+"在吃狗糧");}
}
class Animal{public String name;public int age;public Animal(String name,int age){this.name=name;this.age=age;}public void eat(){System.out.println(this.name+"在吃飯");}
}
public class Test {public static void main(String[] args) {Animal animal=new Dog("旺財",18);animal.eat();}
}
運行代碼
通過上面代碼,我們發現,當我們完成了向上轉型之后,我們通過父類的引用去調用重寫的方法時,程序在編譯時,調用的確實是父類的eat( )方法。但是由于動態綁定,最終我們看到的是Dog類中的eat( )方法。
?2.3 向下轉型
向下轉型也是發生在繼承的繼承的基礎上,向下轉型就是父類向子類轉換。
?1.向下轉型的優點
通過向下轉型,我們就可以訪問子類中特有的屬性和方法。
代碼演示
class Dog extends Animal{public Dog(String name,int age){super(name, age);}@Override //編譯器中方法重寫的默認注釋public void eat() {System.out.println(this.name+"在吃狗糧");}public void run(){System.out.println(this.name+"會跑");}
}
class Bird extends Animal{public Bird(String name, int age) {super(name, age);}public void eat(){System.out.println(this.name+"在吃鳥糧");}public void fly(){System.out.println(this.name+"會飛");}
}
class Animal{public String name;public int age;public Animal(String name,int age){this.name=name;this.age=age;}public void eat(){System.out.println(this.name+"在吃飯");}
}
public class Test {public static void main(String[] args) {Animal animal=new Dog("旺財",18);Dog dog=(Dog)animal;//要強轉類型dog.run();//Dog類中特有的方法System.out.println("=======");Animal animal2=new Bird("小鳥",12);Bird bird=(Bird) animal2;//要強轉類型bird.fly();//Bird類中特有的方法}
}
運行代碼?
2.向下轉型的缺點
并不是所有的向下轉型都是成功的。
3.多態的使用
了解了向上轉型和多態之后,我們接著來在Java中來體驗多態。
代碼演示
class Dog extends Animal{public Dog(String name,int age){super(name, age);}@Override //編譯器中方法重寫的默認注釋public void eat() {System.out.println(this.name+"在吃狗糧");}
}
class Bird extends Animal{public Bird(String name, int age) {super(name, age);}public void eat(){System.out.println(this.name+"在吃鳥糧");}
}
class Animal{public String name;public int age;public Animal(String name,int age){this.name=name;this.age=age;}public void eat(){System.out.println(this.name+"在吃飯");}
}
public class Test {public static void func(Animal animal){animal.eat();}public static void main(String[] args) {Dog dog=new Dog("旺財",18);func(dog);System.out.println("=======");Bird bird=new Bird("小鳥",12);func(bird);}
}
我們都是通過animal這個引用去調用父類中的eat( )方法,但是由于eat( )對應的對象不同,就調用了各對應子類中的eat( ) 方法,最終導致了結果的不同。這就是多態在Java語言中的體現。?