最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中多態(tài)的實(shí)現(xiàn)原理詳細(xì)解析

 更新時(shí)間:2024年01月29日 09:45:22   作者:程序員小玖  
這篇文章主要介紹了Java中多態(tài)的實(shí)現(xiàn)原理詳細(xì)解析,多態(tài)是面向?qū)ο缶幊陶Z(yǔ)言的重要特性,它允許基類(lèi)的指針或引用指向派生類(lèi)的對(duì)象,而在具體訪問(wèn)時(shí)實(shí)現(xiàn)方法的動(dòng)態(tài)綁定,需要的朋友可以參考下

Java多態(tài)概述

多態(tài)是面向?qū)ο缶幊陶Z(yǔ)言的重要特性,它允許基類(lèi)的指針或引用指向派生類(lèi)的對(duì)象,而在具體訪問(wèn)時(shí)實(shí)現(xiàn)方法的動(dòng)態(tài)綁定。

Java 對(duì)于方法調(diào)用動(dòng)態(tài)綁定的實(shí)現(xiàn)主要依賴(lài)于方法表,但通過(guò)類(lèi)引用調(diào)用(invokevitual)和接口引用調(diào)用(invokeinterface)的實(shí)現(xiàn)則有所不同。

類(lèi)引用調(diào)用的大致過(guò)程為:Java編譯器將Java源代碼編譯成class文件,在編譯過(guò)程中,會(huì)根據(jù)靜態(tài)類(lèi)型將調(diào)用的符號(hào)引用寫(xiě)到class文件中。

在執(zhí)行時(shí),JVM根據(jù)class文件找到調(diào)用方法的符號(hào)引用,然后在靜態(tài)類(lèi)型的方法表中找到偏移量,然后根據(jù)this指針確定對(duì)象的實(shí)際類(lèi)型,使用實(shí)際類(lèi)型的方法表,偏移量跟靜態(tài)類(lèi)型中方法表的偏移量一樣,如果在實(shí)際類(lèi)型的方法表中找到該方法,則直接調(diào)用,否則,認(rèn)為沒(méi)有重寫(xiě)父類(lèi)該方法。按照繼承關(guān)系從下往上搜索。 

接口引用調(diào)用后面再說(shuō)吧。

從上圖可以看出,當(dāng)程序運(yùn)行時(shí),需要某個(gè)類(lèi)時(shí),類(lèi)載入子系統(tǒng)會(huì)將相應(yīng)的class文件載入到JVM中,并在內(nèi)部建立該類(lèi)的類(lèi)型信息(這個(gè)類(lèi)型信息其實(shí)就是class文件在JVM中存儲(chǔ)的一種數(shù)據(jù)結(jié)構(gòu)),包含java類(lèi)定義的所有信息,包括方法代碼,類(lèi)變量、成員變量、以及本博文要重點(diǎn)討論的方法表。這個(gè)類(lèi)型信息就存儲(chǔ)在方法區(qū)。 

注意,這個(gè)方法區(qū)中的類(lèi)型信息跟在堆中存放的class對(duì)象是不同的。

在方法區(qū)中,這個(gè)class的類(lèi)型信息只有唯一的實(shí)例(所以是各個(gè)線程共享的內(nèi)存區(qū)域),而在堆中可以有多個(gè)該class對(duì)象??梢酝ㄟ^(guò)堆中的class對(duì)象訪問(wèn)到方法區(qū)中類(lèi)型信息。就像在java反射機(jī)制那樣,通過(guò)class對(duì)象可以訪問(wèn)到該類(lèi)的所有信息一樣。

重點(diǎn)

方法表是實(shí)現(xiàn)動(dòng)態(tài)調(diào)用的核心。上面講過(guò)方法表存放在方法區(qū)中的類(lèi)型信息中。為了優(yōu)化對(duì)象調(diào)用方法的速度,方法區(qū)的類(lèi)型信息會(huì)增加一個(gè)指針,該指針指向一個(gè)記錄該類(lèi)方法的方法表,方法表中的每一個(gè)項(xiàng)都是對(duì)應(yīng)方法的指針。 這些方法中包括從父類(lèi)繼承的所有方法以及自身重寫(xiě)(override)的方法。

拓展

方法區(qū):方法區(qū)和JAVA堆一樣,是各個(gè)線程共享的內(nèi)存區(qū)域,用于存儲(chǔ)已被虛擬機(jī)加載的類(lèi)信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。  運(yùn)行時(shí)常量池:它是方法區(qū)的一部分,Class文件中除了有類(lèi)的版本、方法、字段等描述信息外,還有一項(xiàng)信息是常量池,用于存放編譯器生成的各種符號(hào)引用,這部分信息在類(lèi)加載時(shí)進(jìn)入方法區(qū)的運(yùn)行時(shí)常量池中。  方法區(qū)的內(nèi)存回收目標(biāo)是針對(duì)常量池的回收及對(duì)類(lèi)型的卸載。

Java 的方法調(diào)用方式

Java 的方法調(diào)用有兩類(lèi),動(dòng)態(tài)方法調(diào)用與靜態(tài)方法調(diào)用。

靜態(tài)方法調(diào)用是指對(duì)于類(lèi)的靜態(tài)方法的調(diào)用方式,是靜態(tài)綁定的動(dòng)態(tài)方法調(diào)用需要有方法調(diào)用所作用的對(duì)象,是動(dòng)態(tài)綁定的。

類(lèi)調(diào)用 (invokestatic) 是在編譯時(shí)就已經(jīng)確定好具體調(diào)用方法的情況。

實(shí)例調(diào)用 (invokevirtual)則是在調(diào)用的時(shí)候才確定具體的調(diào)用方法,這就是動(dòng)態(tài)綁定,也是多態(tài)要解決的核心問(wèn)題。

JVM 的方法調(diào)用指令有四個(gè),分別是 invokestatic,invokespecial,invokesvirtual 和 invokeinterface。前兩個(gè)是靜態(tài)綁定,后兩個(gè)是動(dòng)態(tài)綁定的。本文也可以說(shuō)是對(duì)于JVM后兩種調(diào)用實(shí)現(xiàn)的考察。

方法表與方法調(diào)用

如有類(lèi)定義 Person, Girl, Boy

class Person {
    public String toString() {
        return "I'm a person.";
    }
    public void eat() {
    }
    public void speak() {
    }
}
class Boy extends Person {
    public String toString() {
        return "I'm a boy";
    }
    public void speak() {
    }
    public void fight() {
    }
}
class Girl extends Person {
    public String toString() {
        return "I'm a girl";
    }
    public void speak() {
    }
    public void sing() {
    }
}

當(dāng)這三個(gè)類(lèi)被載入到 Java 虛擬機(jī)之后,方法區(qū)中就包含了各自的類(lèi)的信息。Girl 和 Boy 在方法區(qū)中的方法表可表示如下:

可以看到,Girl 和 Boy 的方法表包含繼承自 Object 的方法,繼承自直接父類(lèi) Person 的方法及各自新定義的方法。注意方法表?xiàng)l目指向的具體的方法地址,如 Girl 繼承自 Object 的方法中,只有 toString() 指向自己的實(shí)現(xiàn)(Girl 的方法代碼),其余皆指向 Object 的方法代碼;其繼承自于 Person 的方法 eat() 和 speak() 分別指向 Person 的方法實(shí)現(xiàn)和本身的實(shí)現(xiàn)。

如果子類(lèi)改寫(xiě)了父類(lèi)的方法,那么子類(lèi)和父類(lèi)的那些同名的方法共享一個(gè)方法表項(xiàng)。

因此,方法表的偏移量總是固定的。所有繼承父類(lèi)的子類(lèi)的方法表中,其父類(lèi)所定義的方法的偏移量也總是一個(gè)定值。 Person 或 Object中的任意一個(gè)方法,在它們的方法表和其子類(lèi) Girl 和 Boy 的方法表中的位置 (index) 是一樣的。這樣 JVM 在調(diào)用實(shí)例方法其實(shí)只需要指定調(diào)用方法表中的第幾個(gè)方法即可。

如調(diào)用如下:

class Party {
    void happyHour() {
        Person girl = new Girl();
        girl.speak();
    }
}

當(dāng)編譯 Party 類(lèi)的時(shí)候,生成 girl.speak()的方法調(diào)用假設(shè)為:

Invokevirtual #12

設(shè)該調(diào)用代碼對(duì)應(yīng)著 girl.speak(); #12 是 Party 類(lèi)的常量池的索引。JVM 執(zhí)行該調(diào)用指令的過(guò)程如下所示:

(1)在常量池(這里有個(gè)錯(cuò)誤,上圖為ClassReference常量池而非Party的常量池)中找到方法調(diào)用的符號(hào)引用 。

(2)查看Person的方法表,得到speak方法在該方法表的偏移量(假設(shè)為15),這樣就得到該方法的直接引用。 

(3)根據(jù)this指針得到具體的對(duì)象(即 girl 所指向的位于堆中的對(duì)象)。

(4)根據(jù)對(duì)象得到該對(duì)象對(duì)應(yīng)的方法表,根據(jù)偏移量15查看有無(wú)重寫(xiě)(override)該方法,如果重寫(xiě),則可以直接調(diào)用(Girl的方法表的speak項(xiàng)指向自身的方法而非父類(lèi));如果沒(méi)有重寫(xiě),則需要拿到按照繼承關(guān)系從下往上的基類(lèi)(這里是Person類(lèi))的方法表,同樣按照這個(gè)偏移量15查看有無(wú)該方法。

接口調(diào)用

因?yàn)?nbsp;Java 類(lèi)是可以同時(shí)實(shí)現(xiàn)多個(gè)接口的,而當(dāng)用接口引用調(diào)用某個(gè)方法的時(shí)候,情況就有所不同了。

Java 允許一個(gè)類(lèi)實(shí)現(xiàn)多個(gè)接口,從某種意義上來(lái)說(shuō)相當(dāng)于多繼承,這樣同樣的方法在基類(lèi)和派生類(lèi)的方法表的位置就可能不一樣了

interface IDance {
    void dance();
}
class Person {
    public String toString() {
        return "I'm a person.";
    }
    public void eat() {
    }
    public void speak() {
    }
}
class Dancer extends Person implements IDance {
    public String toString() {
        return "I'm a dancer.";
    }
    public void dance() {
    }
}
class Snake implements IDance {
    public String toString() {
        return "A snake.";
    }
    public void dance() {
        //snake dance  
    }
}

可以看到,由于接口的介入,繼承自于接口 IDance 的方法 dance()在類(lèi) Dancer 和 Snake 的方法表中的位置已經(jīng)不一樣了,顯然我們無(wú)法僅根據(jù)偏移量來(lái)進(jìn)行方法的調(diào)用。

Java 對(duì)于接口方法的調(diào)用是采用搜索方法表的方式,如,要在Dancer的方法表中找到dance()方法,必須搜索Dancer的整個(gè)方法表。

因?yàn)槊看谓涌谡{(diào)用都要搜索方法表,所以從效率上來(lái)說(shuō),接口方法的調(diào)用總是慢于類(lèi)方法的調(diào)用的。

到此這篇關(guān)于Java中多態(tài)的實(shí)現(xiàn)原理詳細(xì)解析的文章就介紹到這了,更多相關(guān)Java多態(tài)的實(shí)現(xiàn)原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實(shí)現(xiàn)求解一元n次多項(xiàng)式的方法示例

    Java實(shí)現(xiàn)求解一元n次多項(xiàng)式的方法示例

    這篇文章主要介紹了Java實(shí)現(xiàn)求解一元n次多項(xiàng)式的方法,涉及java高斯消元法處理矩陣運(yùn)算解多項(xiàng)式的相關(guān)操作技巧,需要的朋友可以參考下
    2018-01-01
  • idea的easyCode的 MybatisPlus模板的配置詳解

    idea的easyCode的 MybatisPlus模板的配置詳解

    這篇文章主要介紹了idea的easyCode的 MybatisPlus模板的配置詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Java枚舉(Enum)從基礎(chǔ)到高級(jí)應(yīng)用詳解

    Java枚舉(Enum)從基礎(chǔ)到高級(jí)應(yīng)用詳解

    文章詳細(xì)介紹了Java枚舉(enum)的概念、基礎(chǔ)語(yǔ)法、內(nèi)置方法及高級(jí)用法,強(qiáng)調(diào)了枚舉在提高代碼類(lèi)型安全性、可讀性和維護(hù)性方面的優(yōu)勢(shì),文中還列舉了添加字段、方法和實(shí)現(xiàn)接口等高級(jí)用法,并提供了命名規(guī)范、不可變性、異常處理等最佳實(shí)踐建議,需要的朋友可以參考下
    2026-05-05
  • 深入理解Spring中RabbitMQ的Channel

    深入理解Spring中RabbitMQ的Channel

    這篇文章主要介紹了深入理解Spring中RabbitMQ的Channel,在RabbitMq中,channel表示邏輯連接或者叫虛擬連接,是棣屬于TCP連接的,一個(gè)TCP連接里可以創(chuàng)建多個(gè)channel,在Rabbit MQ里,消息的發(fā)送和接收都是基于channel的,需要的朋友可以參考下
    2023-08-08
  • Spring控制Bean加載順序的操作方法

    Spring控制Bean加載順序的操作方法

    正常情況下,Spring 容器加載 Bean 的順序是不確定的,那么我們?nèi)绻枰错樞蚣虞d Bean 時(shí)應(yīng)如何操作?本文將詳細(xì)講述我們?nèi)绾尾拍芸刂?nbsp;Bean 的加載順序,需要的朋友可以參考下
    2024-05-05
  • 關(guān)于IDEA2020.1新建項(xiàng)目maven PKIX 報(bào)錯(cuò)問(wèn)題解決方法

    關(guān)于IDEA2020.1新建項(xiàng)目maven PKIX 報(bào)錯(cuò)問(wèn)題解決方法

    這篇文章主要介紹了關(guān)于IDEA2020.1新建項(xiàng)目maven PKIX 報(bào)錯(cuò)問(wèn)題解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • JCrontab簡(jiǎn)單入門(mén)實(shí)例詳解

    JCrontab簡(jiǎn)單入門(mén)實(shí)例詳解

    這篇文章主要為大家詳細(xì)介紹了JCrontab簡(jiǎn)單入門(mén)實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • SpringBoot配置攔截器實(shí)現(xiàn)過(guò)程詳解

    SpringBoot配置攔截器實(shí)現(xiàn)過(guò)程詳解

    在系統(tǒng)中經(jīng)常需要在處理用戶(hù)請(qǐng)求之前和之后執(zhí)行一些行為,例如檢測(cè)用戶(hù)的權(quán)限,或者將請(qǐng)求的信息記錄到日志中,即平時(shí)所說(shuō)的"權(quán)限檢測(cè)"及"日志記錄",下面這篇文章主要給大家介紹了關(guān)于在SpringBoot項(xiàng)目中整合攔截器的相關(guān)資料,需要的朋友可以參考下
    2022-10-10
  • java 中使用匿名類(lèi)直接new接口詳解及實(shí)例代碼

    java 中使用匿名類(lèi)直接new接口詳解及實(shí)例代碼

    這篇文章主要介紹了java 中使用匿名類(lèi)直接new接口詳解及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • java如何利用FastJSON、Gson、Jackson三種Json格式工具自定義時(shí)間序列化

    java如何利用FastJSON、Gson、Jackson三種Json格式工具自定義時(shí)間序列化

    本篇文章主要介紹了java如何利用FastJSON、Gson、Jackson三種Json格式工具自定義時(shí)間序列化,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-08-08

最新評(píng)論

土默特左旗| 青阳县| 湘潭市| 大城县| 新闻| 泗水县| 油尖旺区| 乌拉特前旗| 宾川县| 东乌珠穆沁旗| 盐津县| 静乐县| 嘉义县| 抚顺市| 巨鹿县| 饶阳县| 兴文县| 镇远县| 芦溪县| 泰和县| 湘潭市| 桦南县| 西安市| 营山县| 洞口县| 黄山市| 曲阳县| 汝城县| 景德镇市| 登封市| 突泉县| 容城县| 明光市| 琼结县| 宜阳县| 弥渡县| 河池市| 将乐县| 班玛县| 聂荣县| 南汇区|