繼承是爲了重用父類代碼。兩個類若存在IS-A的關係就可使用繼承。同時繼承也爲實現多態作了鋪墊。php
多態就是指程序中定義的引用變量所指向的具體類型和經過該引用變量發出的方法調用在編程時並不肯定,而是在程序運行期間才肯定,即一個引用變量倒底會指向哪一個類的實例對象,該引用變量發出的方法調用究竟是哪一個類中實現的方法,必須在由程序運行期間才能決定。由於在程序運行時才肯定具體的類,這樣,不用修改源程序代碼,就可讓引用變量綁定到各類不一樣的類實現上,從而致使該引用調用的具體方法隨之改變,即不修改程序代碼就能夠改變程序運行時所綁定的具體代碼,讓程序能夠選擇多個運行狀態,這就是多態性。java
多態,簡而言之就是同一個行爲具備多個不一樣表現形式或形態的能力。好比說,有一杯水,我不知道它是溫的、冰的仍是燙的,可是我一摸我就知道了。我摸水杯這個動做,對於不一樣溫度的水,就會獲得不一樣的結果。這就是多態。
編程
對於java而言,多態的實現機制遵循一個原則:當父類對象引用變量引用子類對象時,被引用對象的類型而不是引用變量的類型決定了調用誰的成員方法,可是這個被調用的方法必須是在父類中定義過的,也就是被子類覆蓋的方法。bash
子類引用的對象轉換成父類類型成爲向上轉型。通俗的說就是將子類對象轉成父類對象。此處父類對象能夠是接口。ui
public class Animal {
public void eat(){
System.out.println("animal eatting...");
}
}
public class Cat extends Animal{
public void eat(){
System.out.println("貓吃魚");
}
}
public class Dog extends Animal{
public void eat(){
System.out.println("狗吃骨頭");
}
public void run(){
System.out.println("我會跑");
}
}
public class Main {
public static void main(String[] args) {
animal = new Dog();//向上轉型
animal.eat();
}
}複製代碼
輸出:狗吃骨頭複製代碼
這就是向上轉型,Animal animal = new Dog();將子類對象Dog轉化爲父類對象Animal。這個時候animal這個引用調用的方法是子類方法。
this
animal.run()
會報錯。Dog d = (Dog)new Animal()
這樣是不行的。與向上轉型相對應的就是向下轉型了。向下轉型是把父類對象轉爲子類對象。(請注意!這裏是有坑的。)
spa
//仍是上面的animal和cat dog
Animal a = new Cat();
Cat c = ((Cat) a);
c.eat();
//輸出 我吃魚
Dog d = ((Dog) a);
d.eat();
// 報錯 : java.lang.ClassCastException:com.chengfan.animal.Cat cannot be cast to com.chengfan.animal.Dog
Animal a1 = new Animal();
Cat c1 = ((Cat) a1);
c1.eat();
// 報錯 : java.lang.ClassCastException:com.chengfan.animal.Animal cannot be cast to com.chengfan.animal.Cat
複製代碼
爲何第一段代碼不報錯呢,由於a自己就是Cat對象,因此固然能夠轉型爲Cat,由於是Cat因此不能轉爲Dog。code
而a1是Anmail對象,它不能向下轉型Wie任何子類對象。好比發現一個古生物化石,知道它是一種動物,但你不能直接說他是貓或者他是狗。對象
向下轉型注意事項繼承
向下轉型只能轉型爲本類對象(貓是不能變成狗的)。
instanceof 關鍵字:instanceof是Java、php的一個二元操做符(運算符),和==,>,<是同一類東西。因爲它是由字母組成的,因此也是Java的保留關鍵字。它的做用是判斷其左邊對象是否爲其右邊類的實例,返回boolean類型的數據。能夠用來判斷繼承中的子類的實例是否爲父類的實現。
instanceof通常放在類型轉換的前面,合理規避異常產生!
public void eat(Animal a){
/*
* 向下轉型(強制轉型)
* 子類引用指向父類的實例(對象),此處必須今習慣強制類型轉換
* 該實例能夠調用子類特有的方法
* 必須知足轉型條件才能轉換(),子類間不能隨意強制轉換,可是子類引用指向父類實例,能夠強制轉換
* instanceof運算符:返回true/false,
*/
if(a instanceof Dog){
Dog d = (Dog)a;
d.eat();
d.run();//狗有一個跑的方法
}
if(a instanceof Cat){
Cat c = (Cat)a;
c.eat();
System.out.println("我也想跑,可是不會"); //貓會抱怨
}
a.eat();//其餘動物只會吃
}
eat(new Cat());
eat(new Cat());
eat(new Dog());複製代碼
向下轉型花木蘭替父親花弧從軍。那麼這時候花木蘭是子類,花弧是父類。花弧有本身的成員屬性年齡,姓名,性別。花木蘭也有這些屬性,可是很明顯兩者的屬性徹底不同。花弧有本身的非靜態成員方法‘騎馬殺敵’,一樣花木蘭也遺傳了父親同樣的方法‘騎馬殺敵’。花弧還有一個靜態方法‘自我介紹’,每一個人均可以問花弧姓甚名誰。同時花木蘭還有一個本身特有的非靜態成員方法‘塗脂抹粉’。可是,如今花木蘭替父從軍,女扮男裝。這時候至關於父類的引用(花弧這個名字)指向了子類對象(花木蘭這我的),那麼在其餘類(其餘的人)中訪問子類對象(花木蘭這我的)的成員屬性(姓名,年齡,性別)時,其實看到的都是花木蘭她父親的名字(花弧)、年齡(60歲)、性別(男)。當訪問子類對象(花木蘭這我的)的非靜態成員方法(騎馬打仗)時,其實都是看到花木蘭本身運用十八般武藝在騎馬打仗。當訪問花木蘭的靜態方法時(自我介紹),花木蘭本身都是用她父親的名字信息在向別人做自我介紹。而且這時候花木蘭不能使用本身特有的成員方法‘塗脂抹粉’。
-----多態中的向上轉型 那麼終於一將功成萬骨枯,打仗旗開得勝了,花木蘭告別了戰爭生活。有一天,遇到了本身心愛的男人,這時候愛情的力量將父類對象的引用(花弧這個名字)強制轉換爲子類對象原本的引用(花木蘭這個名字),那麼花木蘭又重新成爲了她本身,這時候她徹底是她本身了。名字是花木蘭,年齡是28,性別是女,打仗依然那樣生猛女漢子,自我介紹則堂堂正正地告訴別人我叫花木蘭。OMG!終於,終於可使用本身特有的成員方法‘塗脂抹粉’了。今後,花木蘭徹底回到了替父從軍前的那個花木蘭了。而且和本身心愛的男人幸福的過完了一輩子。-----多態中的向下轉型
你們記得哈,向上轉型向下轉型必定是在多態這個前提下哈,不然強制將女兒變成父親,或者將父親變成女人,就變成東方不敗了,系統此時就會報錯非法類型轉換。哈哈哈哈哈。另外開發中通常是利用多態聲明形式參數,並將建立子類的匿名對象做爲實際參數。以上。
public class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
public class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
public class C extends B{
}
public class D extends B{
}
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println("1--" + a1.show(b));
System.out.println("2--" + a1.show(c));
System.out.println("3--" + a1.show(d));
System.out.println("4--" + a2.show(b));
System.out.println("5--" + a2.show(c));
System.out.println("6--" + a2.show(d));
System.out.println("7--" + b.show(b));
System.out.println("8--" + b.show(c));
System.out.println("9--" + b.show(d));
}
}複製代碼
1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D複製代碼
分析這個題須要記住如下幾點
當父類對象引用變量引用子類對象時,被引用對象的類型決定了調用誰的成員方法,
引用變量類型決定可調用的方法。若是子類中沒有覆蓋該方法,那麼會去父類中尋找。複製代碼
先看一個例子
class X {
public void show(Y y){
System.out.println("x and y");
}
public void show(){
System.out.println("only x");
}
}
class Y extends X {
public void show(Y y){
System.out.println("y and y");
}
public void show(int i){
}
}
class main{
public static void main(String[] args) {
X x = new Y();
x.show(new Y());
x.show();
}
}
//結果
//y and y
//only x
複製代碼
其實在繼承鏈中對象方法的調用存在一個優先級:this.show(O)、super.show(O)、
this.show((super)O)、super.show((super)O)。複製代碼
Y繼承了X,覆蓋了X中的show(Y y)方法,可是沒有覆蓋show()方法。
這個時候,引用類型爲X的x指向的對象爲Y,這個時候,調用的方法由Y決定,會先從Y中尋找。執行x.show(new Y());,該方法在Y中定義了,因此執行的是Y裏面的方法;
可是執行x.show();的時候,有的人會說,Y中沒有這個方法啊?它好像是去父類中找該方法了,由於調用了X中的方法。
事實上,Y類中是有show()方法的,這個方法繼承自X,只不過沒有覆蓋該方法,因此沒有在Y中明確寫出來而已,看起來像是調用了X中的方法,實際上調用的仍是Y中的。
這個時候再看上面那句難理解的話就不難理解了吧。X是引用變量類型,它決定哪些方法能夠調用;show()和show(Y y)能夠調用,而show(int i)不能夠調用。Y是被引用對象的類型,它決定了調用誰的方法:調用y的方法。
abcd的關係是這樣的:C/D ---> B ---> A
本篇文章的內容大致上就是這些了。咱們來總結一下。