国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

目錄
多態(tài)
1. 向轉(zhuǎn)型
忘記對象類型
2.顯露優(yōu)勢
合理即正確
可擴展性
失靈了?
3.構(gòu)造器與多態(tài)
構(gòu)造器內(nèi)部的多態(tài)行為
首頁 Java Java基礎(chǔ) 這年頭,說自己會Java得會多型

這年頭,說自己會Java得會多型

Sep 15, 2020 pm 04:46 PM
java 多態(tài)性

這年頭,說自己會Java得會多型

相關(guān)學習推薦:java基礎(chǔ)教學

今天,跟往常一樣踩點來到了公司。坐到自己的工位上打開電腦,"又是搬磚的一天"。想歸想,還是"熟練"的打開了 Idea,看了下今天的需求,便敲起了程式碼。咦,這些程式碼是誰寫的,怎麼出現(xiàn)在我的程式碼裡面,而且還是待提交狀態(tài),我記得我沒寫過呀,饒有興趣的看了看:

這年頭,說自己會Java得會多型

這不是多態(tài)嗎,誰在我電腦寫的測試,不禁一陣奇怪。

"你看看這會輸出什麼結(jié)果?"

一陣聲音從身後傳來,因為在思考輸出結(jié)果,也沒在意聲音的來源,繼續(xù)看了看程式碼,便下結(jié)論:

    polygon() before cal()
    square.cal(), border = 2
    polygon() after cal()
    square.square(), border = 4復(fù)制代碼

心裡想:就這?起碼也是名 Java 開發(fā)工程師好嗎,雖然平常搬搬磚,一些基本功還是有的。不禁有點得意了~

"這就是你的答案嗎?看來你也不咋的"

聲音又突然響起,這次我不淡定了,尼瑪!這答案我也是在心裡想的好嗎,誰能看得到啊,而且說得話讓人那麼想施展一套阿威十八式。 "你是誰???"帶著絲微疑惑和憤怒轉(zhuǎn)過頭了。怎麼沒人?容不得我疑惑半分,"小菜,醒醒,你怎麼上班時間就睡著了"

上班時間,睡著了?我睜開了眼,看了下周圍環(huán)境,原來是夢啊,舒了一口氣。望眼看到部門主管站在我面前,上班時間睡覺,你是身體不舒服還是咋樣?昨天寫了一堆 bug 沒改,今天又提交什麼亂七八糟的東西上去,我看你這個月的績效是不想要的,而且基於你的表現(xiàn),我也要開始為部門考慮考慮了。

"我不是,我沒有,我也不知道怎麼就睡著了,你聽我解釋啊!" 這句話還沒來得及說出口,心裡的花我要帶你回家,在那深夜酒吧哪管它是真是假,請你盡情搖擺忘記鍾意的他,你是最迷人噶,你知道嗎,鬧鐘響了起來,我一下子立起身子,背部微濕,額頂微汗,看了下手機,週六,8點30分,原來那是夢??!

奇怪,怎麼會做那麼奇怪的夢,也太嚇人了。然後就想到了夢中的那部分程式碼,難道我的結(jié)果是錯的嗎?憑著記憶,在電腦上重新敲了出來,運行結(jié)果如下:

/*
    polygon() before cal()
    square.cal(), border = 0
    polygon() after cal()
    square.square(), border = 4
*/復(fù)制代碼

square.cal(), border的結(jié)果居然是 0,而不是2。難道我現(xiàn)在連多型都不會了嗎?電腦手機前的你,不知道是否得出正確答案了呢!不管有沒有,接下來就跟小菜一起來複習一下多型吧!

有些小夥伴疑惑的點可能不只square.cal(), border的結(jié)果是0,也有為什麼不是 square.square(), border = 4先輸出的疑惑。那我們就帶著疑惑,整起!

多態(tài)

在物件導(dǎo)向的程式設(shè)計語言中,多型是繼資料抽象化和繼承之後的第三種基本特徵。

多態(tài)不僅能夠改善程式碼的組織結(jié)構(gòu)和可讀性,還能夠創(chuàng)建可擴充的程式。多態(tài)的作用就是消除型別之間的耦合關(guān)係。

1. 向轉(zhuǎn)型

根據(jù)里氏代換原則:任何基底類別可以出現(xiàn)的地方,子類別一定可以出現(xiàn)。

物件既可以作為它自己本身的類型使用,也可以作為它的基底類型使用。而這種吧對某個物件的引用視為對其基底類型的引用的做法被稱為 - 向轉(zhuǎn)型。因為父類在子類的上方,子類要引用父類,因此稱為 向上轉(zhuǎn)型

public class Animal {    void eat() {
        System.out.println("Animal eat()");
    }
}class Monkey extends Animal {    void eat() {
        System.out.println(" Monkey eat()");
    }
}class test {    public static void start(Animal animal) {
        animal.eat();
    }    public static void main(String[] args) {
        Monkey monkey = new Monkey();
        start(monkey);
    }
}/* OUTPUT:
Monkey eat()
*/復(fù)制代碼

上述test 類別中的start() 方法接收一個Animal ?的引用,自然也可以接收從Animal 的匯出類別。呼叫eat() 方法的時候,自然而然的使用到 Monkey 中定義的eat()方法,而不需要做任何的型別轉(zhuǎn)換。因為從 Monkey 向上轉(zhuǎn)型到 Animal 只能減少接口,而不會比Animal 的接口更少。

打個不是特別恰當?shù)谋确剑?em>你父親的財產(chǎn)會繼承給你,而你的財產(chǎn)還是你的,總的來說,你的財產(chǎn)不會比你父親的少。

這年頭,說自己會Java得會多型

忘記對象類型

test.start()方法中,定義傳入的是 Animal 的引用,但是卻傳入Monkey,這看起來似乎忘記了Monkey 的對象類型,那么為什么不直接把test類中的方法定義為void start(Monkey monkey),這樣看上去難道不會更直觀嗎。

直觀也許是它的優(yōu)點,但是就會帶來其他問題:Animal不止只有一個Monkey的導(dǎo)出類,這個時候來了個pig ,那么是不是就要再定義個方法為void start(Monkey monkey),重載用得挺溜嘛小伙子,但是未免太麻煩了。懶惰才是開發(fā)人員的天性。

因此這樣就有了多態(tài)的產(chǎn)生

2.顯露優(yōu)勢

方法調(diào)用中分為 靜態(tài)綁定動態(tài)綁定。何為綁定:將一個方法調(diào)用同一個方法主體關(guān)聯(lián)起來被稱作綁定。

  • 靜態(tài)綁定:又稱為前期綁定。是在程序執(zhí)行前進行把綁定。我們平時聽到"靜態(tài)"的時候,不難免想到static關(guān)鍵字,被static關(guān)鍵字修飾后的變量成為靜態(tài)變量,這種變量就是在程序執(zhí)行前初始化的。前期綁定是面向過程語言中默認的綁定方式,例如 C 語言只有一種方法調(diào)用,那就是前期綁定。

引出思考:

public static void start(Animal animal) {
    animal.eat();
}復(fù)制代碼

start()方法中傳入的是Animal 的對象引用,如果有多個Animal的導(dǎo)出類,那么執(zhí)行eat()方法的時候如何知道調(diào)用哪個方法。如果通過前期綁定那么是無法實現(xiàn)的。因此就有了后期綁定

  • 動態(tài)綁定:又稱為后期綁定。是在程序運行時根據(jù)對象類型進行綁定的,因此又可以稱為運行時綁定。而 Java 就是根據(jù)它自己的后期綁定機制,以便在運行時能夠判斷對象的類型,從而調(diào)用正確的方法。

小結(jié):

Java 中除了 staticfinal 修飾的方法之外,都是屬于后期綁定

合理即正確

顯然通過動態(tài)綁定來實現(xiàn)多態(tài)是合理的。這樣子我們在開發(fā)接口的時候只需要傳入 基類 的引用,從而這些代碼對所有 基類 的 導(dǎo)出類 都可以正確的運行。

這年頭,說自己會Java得會多型

其中MonkeyPig、Dog皆是Animal的導(dǎo)出類

Animal animal = new Monkey() 看上去不正確的賦值,但是上通過繼承,Monkey就是一種Animal,如果我們調(diào)用animal.eat()方法,不了解多態(tài)的小伙伴常常會誤以為調(diào)用的是Animaleat()方法,但是最終卻是調(diào)用了Monkey自己的eat()方法。

Animal作為基類,它的作用就是為導(dǎo)出類建立公用接口。所有從Animal繼承出去的導(dǎo)出類都可以有自己獨特的實現(xiàn)行為。

可擴展性

有了多態(tài)機制,我們可以根據(jù)自己的需求對系統(tǒng)添加任意多的新類型,而不需要重載void start(Animal animal)方法。

在一個設(shè)計良好的OOP程序中,大多數(shù)或者所有方法都會遵循start()方法的模型,只與基類接口同行,這樣的程序就是具有可擴展性的,我們可以通過從通用的基類繼承出新的數(shù)據(jù)類型,從而添加一些功能,那些操縱基類接口的方法就不需要任何改動就可以應(yīng)用于新類。

失靈了?

我們先來復(fù)習一下權(quán)限修飾符:

√##√√×default√√××#private×
作用域目前類別用一個package子孫類別其他package
public#√
protected
##√
×######×#############
  • public:所有類可見
  • protected:本類、本包和子類都可見
  • default:本類和本包可見
  • private:本類可見

私有方法帶來的失靈

復(fù)習完我們再來看一組代碼:

public class PrivateScope {    private void f() {
        System.out.println("PrivateScope f()");
    }    public static void main(String[] args) {
        PrivateScope p = new PrivateOverride();
        p.f();
    }
}class PrivateOverride extends PrivateScope {    private void f() {
        System.out.println("PrivateOverride f()");
    }
}/* OUTPUT
 PrivateScope f()
*/復(fù)制代碼

是否感到有點奇怪,為什么這個時候調(diào)用的f()是基類中定義的,而不像上面所述的那樣,通過動態(tài)綁定,從而調(diào)用導(dǎo)出類PrivateOverride中定義的f()。不知道心細的你是否發(fā)現(xiàn),基類中f()方法的修飾是private。沒錯,這就是問題所在,PrivateOverride中定義的f()方法是一個全新的方法,因為private的緣故,對子類不可見,自然也不能被重載。

結(jié)論

只有非 private 修飾的方法才可以被覆蓋

我們通過 Idea 寫代碼的時候,重寫的方法頭上可以標注@Override注解,如果不是重寫的方法,標注@Override注解就會報錯:

這年頭,說自己會Java得會多型

這樣也可以很好的提示我們非重寫方法,而是全新的方法。

域帶來的失靈

當小伙伴看到這里,就會開始認為所有事物(除private修飾)都可以多態(tài)地發(fā)生。然而現(xiàn)實卻不是這樣子的,只有普通的方法調(diào)用才可以是多態(tài)的。這邊是多態(tài)的誤區(qū)所在。

讓我們再看看下面這組代碼:

class Super {    public int field = 0;    public int getField() {        return field;
    }
}class Son extends Super {    public int field = 1;    public int getField() {        return field;
    }    public int getSuperField() {        return super.field;
    }
}class FieldTest {    public static void main(String[] args) {
        Super sup = new Son();
        System.out.println("sup.field:" + sup.field + " sup.getField():" + sup.getField());

        Son son = new Son();
        System.out.println("son.field:" + son.field + " son.getField:" + son.getField() + " son.getSupField:" + son.getSuperField());
    }
}/* OUTPUT
sup.field:0 sup.getField():1
son.field:1 son.getField:1 son.getSupField:0
*/復(fù)制代碼

從上面代碼中我們看到sup.field輸出的值不是 Son 對象中所定義的,而是Super本身定義的。這與我們認識的多態(tài)有點沖突。

這年頭,說自己會Java得會多型

其實不然,當Super對象轉(zhuǎn)型為Son引用時,任何域訪問操作都將由編譯器解析,因此不是多態(tài)的。在本例中,為Super.fieldSon.field分配了不同的存儲空間,而Son類是從Super類導(dǎo)出的,因此,Son實際上是包含兩個稱為field的域:它自己的+Super。

雖然這種問題看上去很令人頭痛,但是我們開發(fā)規(guī)范中,通常會將所有的域都設(shè)置為 private,這樣就不能直接訪問它們,只能通過調(diào)用方法來訪問。

static 帶來的失靈

看到這里,小伙伴們應(yīng)該對多態(tài)有個大致的了解,但是不要掉以輕心哦,還有一種情況也是會出現(xiàn)失靈的,那就是如果某個方法是靜態(tài)的,那么它的行為就不具有多態(tài)性。

老規(guī)矩,我們看下這組代碼:

class StaticSuper {    public static void staticTest() {
        System.out.println("StaticSuper staticTest()");
    }

}class StaticSon extends StaticSuper{    public static void staticTest() {
        System.out.println("StaticSon staticTest()");
    }

}class StaticTest {    public static void main(String[] args) {
        StaticSuper sup = new StaticSon();
        sup.staticTest();
    }
}/* OUTPUT
StaticSuper staticTest()
*/復(fù)制代碼

靜態(tài)方法是與類相關(guān)聯(lián),而非與對象相關(guān)聯(lián)

3.構(gòu)造器與多態(tài)

首先我們需要明白的是構(gòu)造器不具有多態(tài)性,因為構(gòu)造器實際上是static方法,只不過該static的聲明是隱式的。

我們先回到開頭的那段神秘代碼:

這年頭,說自己會Java得會多型

其中輸出結(jié)果是:

/*
    polygon() before cal()
    square.cal(), border = 0
    polygon() after cal()
    square.square(), border = 4
*/復(fù)制代碼

我們可以看到先輸出的是基類polygon中構(gòu)造器的方法。

這是因為基類的構(gòu)造器總是在導(dǎo)出類的構(gòu)造過程中被調(diào)用,而且是按照繼承層次逐漸向上鏈接,以使每個基類的構(gòu)造器都能得到調(diào)用。

這年頭,說自己會Java得會多型

因為構(gòu)造器有一項特殊的任務(wù):檢查對象是否能正確的被構(gòu)造。導(dǎo)出類只能訪問它自己的成員,不能訪問基類的成員(基類成員通常是private類型)。只有基類的構(gòu)造器才具有權(quán)限來對自己的元素進行初始化。因此,必須令所有構(gòu)造器都得到調(diào)用,否則就不可能正確構(gòu)造完整對象。

步驟如下:

  • 調(diào)用基類構(gòu)造器,這個步驟會不斷的遞歸下去,首先是構(gòu)造這種層次結(jié)構(gòu)的根,然后是下一層導(dǎo)出類,...,直到最底層的導(dǎo)出類
  • 按聲明順序調(diào)用成員的初始化方法
  • 調(diào)用導(dǎo)出類構(gòu)造其的主體

打個不是特別恰當?shù)谋确剑?em>你的出現(xiàn)是否先要有你父親,你父親的出現(xiàn)是否先要有你的爺爺,這就是逐漸向上鏈接的方式

構(gòu)造器內(nèi)部的多態(tài)行為

有沒有想過如果在一個構(gòu)造器的內(nèi)調(diào)用正在構(gòu)造的對象的某個動態(tài)綁定方法,那么會發(fā)生什么情況呢? 動態(tài)綁定的調(diào)用是在運行時才決定的,因為對象無法知道它是屬于方法所在的那個類還是那個類的導(dǎo)出類。如果要調(diào)用構(gòu)造器內(nèi)部的一個動態(tài)綁定方法,就要用到那個方法的被覆蓋后的定義。然而因為被覆蓋的方法在對象被完全構(gòu)造之前就會被調(diào)用,這可能就會導(dǎo)致一些難于發(fā)現(xiàn)的隱藏錯誤。

問題引索

一個動態(tài)綁定的方法調(diào)用會向外深入到繼承層次結(jié)構(gòu)內(nèi)部,它可以調(diào)動導(dǎo)出類里的方法,如果我們是在構(gòu)造器內(nèi)部這樣做,那么就可能會調(diào)用某個方法,而這個方法做操縱的成員可能還未進行初始化,這肯定就會招致災(zāi)難的。

敏感的小伙伴是不是想到了開頭的那段代碼:

這年頭,說自己會Java得會多型

輸出結(jié)果是:

/*
    polygon() before cal()
    square.cal(), border = 0
    polygon() after cal()
    square.square(), border = 4
*/復(fù)制代碼

我們在進行square對象初始化的時候,會先進行polygon對象的初始化,在polygon構(gòu)造器中有個cal()方法,這個時候就采用了動態(tài)綁定機制,調(diào)用了squarecal(),但這個時候border這個變量尚未進行初始化,int 類型的默認值為 0,因此就有了square.cal(), border = 0的輸出??吹竭@里,小伙伴們是不是有種撥開云霧見青天的感覺!

這組代碼初始化的實際過程為:

  • 在其他任何事物發(fā)生之前,將分配給對象的存儲空間初始化成二進制的零
  • 調(diào)用基類構(gòu)造器時,會調(diào)用被覆蓋后的cal()方法,由于步驟1的緣故,因此 border 的值為 0
  • 按照聲明的順序調(diào)用成員的初始化方法
  • 調(diào)用導(dǎo)出類的構(gòu)造器主體

不知道下次又會做什么樣的夢~

這年頭,說自己會Java得會多型

想了解更多編程學習,敬請關(guān)注php培訓欄目!

以上是這年頭,說自己會Java得會多型的詳細內(nèi)容。更多資訊請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願投稿,版權(quán)歸原作者所有。本站不承擔相應(yīng)的法律責任。如發(fā)現(xiàn)涉嫌抄襲或侵權(quán)的內(nèi)容,請聯(lián)絡(luò)admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Laravel 教程
1601
29
PHP教程
1502
276
如何使用JDBC處理Java的交易? 如何使用JDBC處理Java的交易? Aug 02, 2025 pm 12:29 PM

要正確處理JDBC事務(wù),必須先關(guān)閉自動提交模式,再執(zhí)行多個操作,最後根據(jù)結(jié)果提交或回滾;1.調(diào)用conn.setAutoCommit(false)以開始事務(wù);2.執(zhí)行多個SQL操作,如INSERT和UPDATE;3.若所有操作成功則調(diào)用conn.commit(),若發(fā)生異常則調(diào)用conn.rollback()確保數(shù)據(jù)一致性;同時應(yīng)使用try-with-resources管理資源,妥善處理異常並關(guān)閉連接,避免連接洩漏;此外建議使用連接池、設(shè)置保存點實現(xiàn)部分回滾,並保持事務(wù)盡可能短以提升性能。

了解Java虛擬機(JVM)內(nèi)部 了解Java虛擬機(JVM)內(nèi)部 Aug 01, 2025 am 06:31 AM

TheJVMenablesJava’s"writeonce,runanywhere"capabilitybyexecutingbytecodethroughfourmaincomponents:1.TheClassLoaderSubsystemloads,links,andinitializes.classfilesusingbootstrap,extension,andapplicationclassloaders,ensuringsecureandlazyclassloa

如何使用Java的日曆? 如何使用Java的日曆? Aug 02, 2025 am 02:38 AM

使用java.time包中的類替代舊的Date和Calendar類;2.通過LocalDate、LocalDateTime和LocalTime獲取當前日期時間;3.使用of()方法創(chuàng)建特定日期時間;4.利用plus/minus方法不可變地增減時間;5.使用ZonedDateTime和ZoneId處理時區(qū);6.通過DateTimeFormatter格式化和解析日期字符串;7.必要時通過Instant與舊日期類型兼容;現(xiàn)代Java中日期處理應(yīng)優(yōu)先使用java.timeAPI,它提供了清晰、不可變且線

比較Java框架:Spring Boot vs Quarkus vs Micronaut 比較Java框架:Spring Boot vs Quarkus vs Micronaut Aug 04, 2025 pm 12:48 PM

前形式攝取,quarkusandmicronautleaddueTocile timeProcessingandGraalvSupport,withquarkusoftenpernperforminglightbetterine nosserless notelless centarios.2。

了解網(wǎng)絡(luò)端口和防火牆 了解網(wǎng)絡(luò)端口和防火牆 Aug 01, 2025 am 06:40 AM

NetworkPortSandFireWallsworkTogetHertoEnableCommunication whereSeringSecurity.1.NetWorkPortSareVirtualendPointSnumbered0-655 35,with-Well-with-Newonportslike80(HTTP),443(https),22(SSH)和25(smtp)sindiessingspefificservices.2.portsoperateervertcp(可靠,c

垃圾收集如何在Java工作? 垃圾收集如何在Java工作? Aug 02, 2025 pm 01:55 PM

Java的垃圾回收(GC)是自動管理內(nèi)存的機制,通過回收不可達對象釋放堆內(nèi)存,減少內(nèi)存洩漏風險。 1.GC從根對象(如棧變量、活動線程、靜態(tài)字段等)出發(fā)判斷對象可達性,無法到達的對像被標記為垃圾。 2.基於標記-清除算法,標記所有可達對象,清除未標記對象。 3.採用分代收集策略:新生代(Eden、S0、S1)頻繁執(zhí)行MinorGC;老年代執(zhí)行較少但耗時較長的MajorGC;Metaspace存儲類元數(shù)據(jù)。 4.JVM提供多種GC器:SerialGC適用於小型應(yīng)用;ParallelGC提升吞吐量;CMS降

比較Java構(gòu)建工具:Maven vs. Gradle 比較Java構(gòu)建工具:Maven vs. Gradle Aug 03, 2025 pm 01:36 PM

Gradleisthebetterchoiceformostnewprojectsduetoitssuperiorflexibility,performance,andmoderntoolingsupport.1.Gradle’sGroovy/KotlinDSLismoreconciseandexpressivethanMaven’sverboseXML.2.GradleoutperformsMaveninbuildspeedwithincrementalcompilation,buildcac

以身作則,解釋說明 以身作則,解釋說明 Aug 02, 2025 am 06:26 AM

defer用於在函數(shù)返回前執(zhí)行指定操作,如清理資源;參數(shù)在defer時立即求值,函數(shù)按後進先出(LIFO)順序執(zhí)行;1.多個defer按聲明逆序執(zhí)行;2.常用於文件關(guān)閉等安全清理;3.可修改命名返回值;4.即使發(fā)生panic也會執(zhí)行,適合用於recover;5.避免在循環(huán)中濫用defer,防止資源洩漏;正確使用可提升代碼安全性和可讀性。

See all articles