中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

云網站開發(fā)東莞快速排名

云網站開發(fā),東莞快速排名,租賃空間網站建設,安居客做網站目錄 1. 向上轉型和向下轉型 1.1 向上轉型 1.2 向下轉型 1.3 instanceof關鍵字 2. 重寫(overidde) 2.1 方法重寫的規(guī)則 2.1.1 基礎規(guī)則 2.1.2 深層規(guī)則 2.2 三種不能重寫的方法 final修飾 private修飾 static修飾 3. 動態(tài)綁定 3.1 動態(tài)綁…

目錄

1. 向上轉型和向下轉型

1.1 向上轉型

1.2?向下轉型

1.3 instanceof關鍵字

2. 重寫(overidde)

2.1 方法重寫的規(guī)則

2.1.1 基礎規(guī)則

2.1.2 深層規(guī)則

2.2 三種不能重寫的方法

final修飾

private修飾?

static修飾

3. 動態(tài)綁定

3.1 動態(tài)綁定的概念

3.2 動態(tài)綁定與靜態(tài)綁定

4. 多態(tài)

4.1 多態(tài)的實現(xiàn)場景

1. 基類形參方法?

2. 基數(shù)組

4.2 多態(tài)缺陷

1. 屬性(字段)沒有多態(tài)性?

2. 向上轉型不能使用子類特有的方法

3. 構造方法沒有多態(tài)性


上一篇文章中,我們深度學習了繼承的概念與實現(xiàn)。在繼承篇中,我們最重要的就是“弄清楚通過子類實例變量來訪問與父類相同的成員會怎么樣”;而在多態(tài)篇中,最核心的內容就是“弄清楚通過父類實例變量來訪問與子類相同的方法會怎么樣”。

1. 向上轉型和向下轉型

在了解多態(tài)之前,我們還要補充幾個知識點,這首先就是向上轉型和向下轉型。

1.1 向上轉型

向上轉型是指將一個子類對象的引用賦值給一個父類類型的實例變量

語法格式:

父類類型 對象名 = new 子類類型();

//例如?Animal animal = new Cat("小咪", 2);

animal是父類類型的實例變量,但引用的是一個子類Cat對象,因為這是從小范圍向大范圍的轉換。類似基礎數(shù)據(jù)類型中的隱式類型轉換(例如長整形long接收整形int的數(shù)據(jù))


向上轉型的3種使用場景:

  1. 直接賦值:子類對象的引用直接賦值給父類類型的實例變量。
  2. 方法傳參:子類對象的引用作為參數(shù),傳遞給方法中的父類類型的形參
  3. 方法返回:方法的返回類型是父類類型返回的值是子類類型。

例如:

public class TestAnimal {// 2. 方法傳參:形參為父類型引用,可以接收任意子類的對象public static void eatFood(Animal a){a.eat();}// 3. 作返回值:返回任意子類對象public static Animal buyAnimal(String var){if("狗".equals(var) ){return new Dog("狗狗",1);}else if("貓" .equals(var)){return new Cat("貓貓", 1);}else{return null;}}public static void main(String[] args) {Animal cat = new Cat("元寶",2);   // 1. 直接賦值:子類對象賦值給父類對象Dog dog = new Dog("小七", 1);eatFood(cat);eatFood(dog);Animal animal = buyAnimal("狗");animal.eat();animal = buyAnimal("貓");animal.eat();}}

1.2?向下轉型

向下轉型是將父類對象強制轉換為子類對象的過程,需要用到類型轉換運算符( ) 。

【注意】

  • 只能對已向上轉型的對象進行向下轉型:不能直接將一個父類對象強制轉換為子類對象,除非這個父類對象實際上是子類對象的向上轉型。也就是說,必須先創(chuàng)建一個子類對象,然后將其向上轉型為父類對象,最后再進行向下轉換。
  • 向上轉型的子類類型 與 向下接收的子類類型必須一致。

例如:

先看父類和子類的具體代碼:

public class Animal {public String name;public Animal(String name){this.name = name;}public void eat(){System.out.println(name+"在吃東西");}
}public class Dog extends Animal{public Dog(String name){super(name);}public void eat(){System.out.println(name+"在吃狗糧");}//Dog類的專屬方法public void bark(){System.out.println(name+"在汪汪叫");}
}public class Cat extends Animal{public Cat(String name){super(name);}public void eat(){System.out.println(name+"在吃貓糧");}//Cat類的專屬方法public void mew(){System.out.println(name+"在喵喵叫");}
}

測試1:父類實例animal是Dag類的向上轉型,再讓animal向下轉型傳給子類實例dog。

public class Test {public static void main(String[] args) {Animal animal = new Dog("旺財");Dog dog;dog = (Dog) animal;dog.bark();}
}

運行成功


測試2:父類實例animal是Dag類的向上轉型,再讓animal向下轉型傳給子類實例cat。(向上轉型的子類與向下接收的子類不一致

public class Test {public static void main(String[] args) {Animal animal = new Dog("旺財");Cat cat;cat = (Cat) animal;//拋出異常}
}

拋出異常


1.3 instanceof關鍵字

向下轉型用的比較少,而且不安全,萬一轉換失敗,運行時就會拋異常。Java中為了提高向下轉型的安全性,引入了instanceof關鍵字。

語法:

? ? ? ? Object? instanceof? ClassName

其中,object?是要測試的對象或實例變量,ClassName?是要測試的類名。

作用和返回值:

如果?object?是?ClassName?的實例其子類的實例,則表達式返回?true;否則返回?false。

有了instanceof,我們向下轉型就可以更安全了:

public class TestAnimal {public static void main(String[] args) {Cat cat = new Cat("元寶",2);Dog dog = new Dog("小七", 1);// 向上轉型Animal animal = cat;animal.eat();animal = dog;animal.eat();if(animal instanceof Cat){    //檢查類型cat = (Cat)animal;cat.mew();}if(animal instanceof Dog){    //檢查類型dog = (Dog)animal;dog.bark();}}}

animal最后是Dog類的引用,所以通過了第2個檢查,由dog接收animal的向下轉型。

2. 重寫(overidde)

2.1 方法重寫的規(guī)則

2.1.1 基礎規(guī)則

方法重寫:也稱為方法覆蓋,即外殼不變,核心重寫。

  1. 子類在重寫父類的方法時,一般必須與父類的方法原型一致【返回值類型、方法名、參數(shù)列表完全一致】。?
  2. 重寫的方法,可以在子類方法頭的上一行使用“ @Override ”注解來顯式指定。有了這個注解能幫我們進行一些合法性校驗。(例如不小心將方法名字拼寫錯了,比如eat寫成 aet,那么此時編譯器就會發(fā)現(xiàn)父類中沒有 aet 方法, 就會編譯報錯, 提示無法構成重寫)

例如:

如果顯示指定@overidde,但方法與父類原型不一致的話,系統(tǒng)會報錯:

2.1.2 深層規(guī)則

  1. 返回值類型:其實子類重寫的方法返回類型也可以與父類不一樣,但是必須是具有父子關系的。???????
    1. ?該要求其實隱藏了一個情況,那就是此時的方法返回值類型是類類型的。
    2. ?對于這種情況的方法重寫,父類方法的返回值類型 必須是 子類方法的返回值類型基類。
  2. 訪問限定符:訪問權限不能比父類中被重寫的方法的訪問權限更低。(即子類重寫的方法訪問權限可以更寬松,不能更嚴格)

對于“返回值類型”要求的舉例:

?class Parent {public Number display() {return 42; // 返回一個Integer類型的值}
}class Child extends Parent {// 重寫父類的display方法,并改變返回類型為Double,這是允許的,因為Double是Number的子類型@Overridepublic Double display() {return 42.0;}
}public class Test {public static void main(String[] args) {Parent parent = new Parent();System.out.println(parent.display()); // 輸出: 42Child child = new Child();System.out.println(child.display()); // 輸出: 42.0}
}

Parent類的display方法的返回類型是Number類,Child類的display方法的返回類型是Double類。其中Parent類是Child類的父類,Number類又是Double類和Interger類的父類,這符合方法重寫的深層規(guī)則。

如果該例子中的 方法返回值類型的父子關系反過來?會報錯:


對于“訪問限定符”要求的舉例:


關于方法重寫還有更深層更嚴格的規(guī)定,這些規(guī)定與異常、線程等有關。本章重點是繼承與多態(tài),所以不再具體展開。

2.2 三種不能重寫的方法

如果父類方法被final、private或static修飾,則子類不能重寫該方法。

final修飾

final:

final修飾成員方法時,就是用來防止該方法被子類重寫 或者 不想讓該方法被重寫。

例如:


private修飾?

private:

父類的方法被private修飾時,說明這個方法是父類私有的,子類也沒有辦法去訪問該方法。

  • 如果private修飾了父類的方法,子類又寫了一個與父類方法原型一樣的方法,系統(tǒng)并不會報錯
    (因為系統(tǒng)檢查方法重寫時,會自動把父類的私有方法忽略掉)
  • 如果private修飾了子類的方法,父類又有一個與子類方法原型一樣的非private方法,那么系統(tǒng)會報錯。
    (此時系統(tǒng)會認為你想要讓子類重寫父類方法,又因為重寫后的方法是私有的而父類的方法非私有,所以會提醒你“分配了更低的訪問權限”并報錯)

例1:

父類方法是私有的,build沒有問題

例2:

子類方法是私有的,父類方法原型與子類一致。系統(tǒng)認為你要重寫,但子類的方法權限更低,所以報錯:


static修飾

static:

靜態(tài)方法是在類加載時就綁定到類本身,而不是在運行時綁定到具體的對象實例,所以static修飾的方法不能被重寫。即靜態(tài)方法不能實現(xiàn)動態(tài)綁定,也就不能被覆蓋(重寫)。

例如:

雖然靜態(tài)方法是可以被繼承的,但如果子類定義了一個與父類相同簽名的靜態(tài)方法這只是對父類靜態(tài)方法的一種隱藏,而非真正意義上的重寫。

  • 子類對象向上轉型后,當通過父類實例變量引用調用該方法時,仍然會執(zhí)行父類的靜態(tài)方法,而不是子類的靜態(tài)方法。

例如:

class Parent {static void display() {System.out.println("Parent display method");}
}class Child extends Parent {static void display() {System.out.println("Child display method");}
}public class Test {public static void main(String[] args) {Parent parent1 = new Parent();parent1.display();  //調用父類靜態(tài)方法Child child = new Child();child.display();   //調用子類靜態(tài)方法Parent parent2 = new Child();   //向上轉型parent2.display();  //調用父類靜態(tài)方法}
}

3. 動態(tài)綁定

3.1 動態(tài)綁定的概念

剛剛在解釋static修飾方法時,我們提到了一個詞叫動態(tài)綁定。下面讓我們看看什么是動態(tài)綁定。

概念:

動態(tài)綁定也叫后期綁定,是指在運行時根據(jù)對象的實際類型來確定調用哪個方法,而不是在編譯時就決定。當一個父類引用指向其子類的對象,并且通過該引用調用一個被重寫的方法時,會在運行時根據(jù)對象的實際類型來調用相應的方法實現(xiàn),這就是重寫方法的動態(tài)綁定。

動態(tài)綁定重寫方法的實現(xiàn)條件:

  1. 存在繼承關系必須有一個基類(父類)和至少一個派生類(子類),子類繼承自父類。
  2. 方法重寫子類要實現(xiàn)父類中至少一個方法的重寫。
  3. 向上轉型在程序中存在向上轉型的情況,即把子類對象的引用賦值給父類的實例變量。

例如:

class Animal {public String name;public Animal(String name){this.name = name;}public void eat(){System.out.println(name+"在吃東西");}
}public class Dog extends Animal{public Dog(String name){super(name);}public void eat(){System.out.println(name+"在吃狗糧");}
}public class Cat extends Animal{public Cat(String name){super(name);}public void eat(){System.out.println(name+"在吃貓糧");}
}public class Test {public static void main(String[] args) {Animal animal = new Animal("動物");//animal動態(tài)綁定到Animal類animal.eat();animal = new Dog("小狗");//animal動態(tài)綁定到Dog類animal.eat();animal = new Cat("小貓");//animal動態(tài)綁定到Cat類animal.eat();}
}

3.2 動態(tài)綁定與靜態(tài)綁定

靜態(tài)綁定也稱為早期綁定:是指在程序編譯時就已經確定了方法調用的具體對象和方法實現(xiàn)。與動態(tài)綁定相對應,靜態(tài)綁定不需要運行時進行額外的判斷和查找來確定調用哪個方法。

靜態(tài)綁定的適用情況

  • 基本數(shù)據(jù)類型的方法調用(可重載的方法):對于基本數(shù)據(jù)類型的操作方法,如數(shù)學運算等,通常是靜態(tài)綁定。例如,int a = 5; int b = 10; int c = a + b;?中?+?運算符對應的加法方法是在編譯時就確定的。
  • 私有方法、靜態(tài)方法和 final 方法:這些方法不能被重寫或具有特殊的性質,所以它們的調用可以在編譯時確定。例如,class Example { private void privateMethod() {...} static void staticMethod() {...} final void finalMethod() {...} }?中的私有方法、靜態(tài)方法和 final 方法都是靜態(tài)綁定的。
  • 構造方法:構造方法在創(chuàng)建對象時被調用,每個類都有特定的構造方法,且在編譯時就可以確定是哪個類的構造方法會被調用。例如,new Example()?會調用 Example 類的構造方法,這是在編譯時就已經決定的。

方法重載(靜態(tài)綁定)是一個類的多態(tài)性表現(xiàn)【例如工具類Arrays】,而方法重寫(動態(tài)綁定)是子類與父類間的多態(tài)性的表現(xiàn)。

4. 多態(tài)

多態(tài)的概念:

去完成某個行為時,當不同的對象去完成時會產生出不同的狀態(tài)。又或者同一件事情,發(fā)生在不同對象身上,就會產生不同的結果。

打個比方,語文老師要求同學們背一首詩,同學A背了一首李白的詩、同學B背了一首杜甫的詩、同學C背了一首李清照的詩……每個同學背的詩都不同,但不管怎么說他們都完成了“背一首詩”的任務,這就是多態(tài)。

4.1 多態(tài)的實現(xiàn)場景

在java中要實現(xiàn)多態(tài),必須要滿足如下幾個條件,缺一不可:

  1. 必須在繼承體系下?
  2. 子類必須要對父類中方法進行重寫?
  3. 通過父類的引用調用

下面我來介紹兩種常見的多態(tài)實現(xiàn)。

1. 基類形參方法?

基類形參方法:指的是形參數(shù)據(jù)類型為基類類型的方法。

該方法的形參的類型是父類類型,我們一般在該方法中使用被重寫的方法。不同的子類實例變量傳參進去并發(fā)生向上轉型,該基類形參方法就能夠通過動態(tài)綁定來調用不同的重寫方法,從而實現(xiàn)多態(tài)。

例如:

//有繼承關系的類
public class Animal {public String name;public Animal(String name){this.name = name;}public void eat(){System.out.println(name+"在吃東西");}
}public class Dog extends Animal{public Dog(String name){super(name);}public void eat(){System.out.println(name+"在吃狗糧");}
}public class Cat extends Animal{public Cat(String name){super(name);}public void eat(){System.out.println(name+"在吃貓糧");}
}
————————————————————————————————————————————————————————
————————————————————————————————————————————————————————
//含基類形參方法的類
public class Test {public void eat(Animal animal){ //基類形參方法animal.eat();}public static void main(String[] args) {Test test = new Test();    //如果Test的eat方法是靜態(tài)方法,那么可以不用new一個Test對象test.eat(new Animal("小動物"));test.eat(new Dog("小狗"));test.eat(new Cat("小貓"));}
}


這種方法有點類似C語言中的函數(shù)指針和回調函數(shù)的用法。詳細請看《指針之旅(4)—— 指針與函數(shù):函數(shù)指針、轉移表、回調函數(shù)》

2. 基數(shù)組

基數(shù)組:指的是數(shù)組元素的類型都是基類類型。

由于可以向上轉型,在基數(shù)組中可以存放子類對象,從而實現(xiàn)多態(tài)。

(有點類似C語言中的函數(shù)指針數(shù)組)

例如:

?//Animal類、Dog類和Cat類的內容如上面的一致
public class Test {public static void main(String[] args) {//基數(shù)組animalsAnimal[] animals = {new Animal("小動物"), new Dog("小狗"), new Cat("小貓")};for(Animal x: animals){x.eat();    //臨時變量x通過動態(tài)綁定實現(xiàn)多態(tài)}}
}

如果有新的動物增加,我們可以在基數(shù)組animals中添加,這就是多態(tài)的好處,十分便捷。

如果不基于多態(tài)來實現(xiàn)剛剛的代碼內容,我們需要多個if-else語句,如下:

在這種情況下,如果要增加一個動物,不僅字符串數(shù)組animals要變,而且在for-each循環(huán)中還要加多一條else-if語句,十分不便。

4.2 多態(tài)缺陷

1. 屬性(字段)沒有多態(tài)性?

當父類和子類都有同名屬性的時候,通過父類實例變量引用只能引用父類自己的成員屬性。

例如:

public class Parent {public String str = "parent";
}public class Child extends Parent{public String str = "child";
}public class Test {public static void main(String[] args) {Parent parent = new Parent();System.out.println(parent.str);//打印parentChild child = new Child();System.out.println(child.str);//打印childparent = child;     //向上轉型System.out.println(parent.str);//屬性沒有多態(tài)性,打印的還是父類的str}
}

2. 向上轉型不能使用子類特有的方法

方法調用在編譯時進行類型檢查,編譯器只檢查引用變量類型中定義的方法,而不考慮實際對象的類型。

例如,這里子類Dog比父類Animal類多了一個特殊方法bark()。如果用Animal類型的實例變量來接收Dog類的對象,我們會發(fā)現(xiàn)無法通過該實例變量調用bark方法:

3. 構造方法沒有多態(tài)性

父類的構造方法中調用一個被重寫的方法時,實際執(zhí)行的是子類中的實現(xiàn)。然而,此時子類可能還未完成初始化,其成員變量尚未賦值或處于默認狀態(tài),這就可能導致程序行為不確定,甚至引發(fā)錯誤。

父類構造方法中如果調用了被重寫的方法,那么該重寫的方法使用的是子類的方法

我們創(chuàng)建兩個類, B 是父類, D 是子類. D 中重寫 func 方法. 并且在 B 的構造方法中調用 func:

?
class B {public B() {// do nothingfunc();}public void func() {System.out.println("B.func()");}
}class D extends B {private int num = 10;@Overridepublic void func() {System.out.println("D.func() " + num);}
}public class Test {public static void main(String[] args) {D d = new D();}
}?

  • 構造 D 對象的同時,會調用 B 的構造方法.
  • B 的構造方法中調用了 func 方法, 此時會觸發(fā)動態(tài)綁定,會調用到 D 中的 func 。此時 D 對象自身還沒有構造,此時 num 處在未初始化的狀態(tài),值為 0.
  • 如果具備多態(tài)性,num的值應該是10.

結論: "用盡量簡單的方式使對象進入可工作狀態(tài)", 盡量不要在構造器中調用方法(如果這個方法被子類重寫, 就會觸 發(fā)動態(tài)綁定, 但是此時子類對象還沒構造完成), 可能會出現(xiàn)一些隱藏的但是又極難發(fā)現(xiàn)的問題。


本期分享完畢,感謝大家的支持Thanks?(・ω・)ノ

http://www.risenshineclean.com/news/22608.html

相關文章:

  • 曲周手機網站建設百度搜索量最大的關鍵詞
  • 供應鏈管理專業(yè)就業(yè)前景東莞seo網絡推廣專
  • 那里可以找建網站的人seo排名怎么做
  • 吉首網站建設廣州 關于進一步優(yōu)化
  • 幫企業(yè)做網站線上推廣的方法
  • 網站優(yōu)化試題現(xiàn)在最好的營銷方式
  • 怎樣免費做彩票網站營銷的方法手段有哪些
  • 建網站流程 知乎最打動人心的廣告語
  • 網上競價投標流程北京百度關鍵詞優(yōu)化
  • 網站軟文制作企業(yè)網站建設平臺
  • 利用百度網盤自動播放做視頻網站會計培訓班的費用是多少
  • 開普網站建設公司免費寫文章的軟件
  • 做公司網站需要幾個域名網絡營銷的特點是什么
  • 甘肅疫情防控最新政策seo怎么優(yōu)化
  • 江油網站網站建設煙臺網站建設
  • 太原網站推廣教程百度搜索量最大的關鍵詞
  • 知名的教育行業(yè)網站開發(fā)推廣app用什么平臺比較好
  • 大邑縣建設局網站深圳開發(fā)公司網站建設
  • 政府職能網站建設seo門戶網價格是多少錢
  • 設計本官方網站下載如何設計網站
  • 開網站賺50萬做百度指數(shù)官方下載
  • 網站項目建設方案河南網絡推廣那家好
  • 大連三合一網站制作百度快照收錄入口
  • WordPress命令執(zhí)行漏洞搜索引擎優(yōu)化簡稱seo
  • 網站推廣優(yōu)化技巧大全優(yōu)化推廣方案
  • 免費建網站 步驟寧波企業(yè)網站seo
  • 上海市建設人才網站鄭州網站優(yōu)化推廣
  • 網站響應式技術蘇州關鍵詞優(yōu)化排名推廣
  • 國外網站空間需要備案嗎鄭州seo優(yōu)化外包熱狗網
  • 樂清建設路小學校園網站在廣州做seo找哪家公司