欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java如何對方法進行調用詳解

 更新時間:2021年06月02日 14:49:39   作者:Tc.l  
今天給大家整理了Java如何對方法進行調用,文中有非常詳細的介紹及代碼示例,對正在學習java的小伙伴們很有幫助,需要的朋友可以參考下

一、方法調用

方法調用的唯一目的:確定要調用哪一個方法

方法調用分為解析調用和分派調用

二、非虛方法與虛方法

非虛方法: 靜態(tài)方法,私有方法,父類中的方法,被final修飾的方法,實例構造器

與之對應不是非虛方法的就是虛方法了

它們都沒有重寫出其他版本的方法,非常適合在類加載階段就進行解析(符號引用->直接引用)

三、調用指令

普通調用指令

  • invokestatic:調用靜態(tài)方法
  • invokespecial:調用私有方法,父類中的方法,實例構造器方法,final方法
  • invokeinterface:調用接口方法
  • invokevirtual: 調用虛方法

使用invokestaticinvokespecial指令的一定是非虛方法

使用invokeinterface指令一定是虛方法(因為接口方法需要具體的實現(xiàn)類去實現(xiàn))

使用invokevirtual指令的是虛方法

動態(tài)調用指令

invokedynamic: 動態(tài)解析出需要調用的方法再執(zhí)行

jdk 7 出現(xiàn)invokedynamic,支持動態(tài)語言

測試虛方法代碼

父類

public class Father {
    public static void staticMethod(){
        System.out.println("father static method");
    }

    public final void finalMethod(){
        System.out.println("father final method");
    }

    public Father() {
        System.out.println("father init method");
    }

    public void overrideMethod(){
        System.out.println("father override method");
    }
}

接口

public interface TestInterfaceMethod {
    void testInterfaceMethod();
}

子類

public class Son extends Father{

    public Son() {
        //invokespecial 調用父類init 非虛方法
        super();
        //invokestatic 調用父類靜態(tài)方法 非虛方法
        staticMethod();
        //invokespecial 調用子類私有方法 特殊的非虛方法
        privateMethod();
        //invokevirtual 調用子類的重寫方法 虛方法
        overrideMethod();
        //invokespecial 調用父類方法 非虛方法
        super.overrideMethod();
        //invokespecial 調用父類final方法 非虛方法
        super.finalMethod();
        //invokedynamic 動態(tài)生成接口的實現(xiàn)類 動態(tài)調用
        TestInterfaceMethod test = ()->{
            System.out.println("testInterfaceMethod");
        };
        //invokeinterface 調用接口方法 虛方法
        test.testInterfaceMethod();
    }

    @Override
    public void overrideMethod(){
        System.out.println("son override method");
    }

    private void privateMethod(){
        System.out.println("son private method");
    }

    public static void main(String[] args) {
        new Son();
    }
}

注意: 接口中的默認方法也是invokeinterface,接口中的靜態(tài)方法是invokestatic

四、解析調用

在編譯就確定了要調用哪個方法,運行時不可以改變

解析調用 調用的是 非虛方法

五、分派調用

分派又分為靜態(tài)分派與動態(tài)分配

早期綁定:解析調用和靜態(tài)分派這種編譯期間可以確定調用哪個方法

晚期綁定: 動態(tài)分派這種編譯期無法確定,要到運行時才能確定調用哪個方法

六、靜態(tài)分派

//  靜態(tài)類型      	 實際類型
	List list = new ArrayList();

靜態(tài)分派: 根據(jù)靜態(tài)類型決定方法執(zhí)行的版本的分派

發(fā)生在編譯期,特殊的解析調用

典型的表現(xiàn)就是方法的重載

public class StaticDispatch {
    public void test(List list){
        System.out.println("list");
    }

    public void test(ArrayList arrayList){
        System.out.println("arrayList");
    }

    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        List list = new ArrayList();
        StaticDispatch staticDispatch = new StaticDispatch();
        staticDispatch.test(list);
        staticDispatch.test(arrayList);
    }
}
/*
list
arrayList
*/

方法的版本并不是唯一的,往往只能確定一個最適合的版本

七、動態(tài)分派

動態(tài)分派:動態(tài)期根據(jù)實際類型確定方法執(zhí)行版本的分派

動態(tài)分派與重寫有著緊密的聯(lián)系

public class DynamicDispatch {
    public static void main(String[] args) {
        Father father = new Father();
        Father son = new Son();

        father.hello();
        son.hello();
    }
    static class Father{
        public void hello(){
            System.out.println("Father hello");
        }
    }

    static class Son extends Father{
        @Override
        public void hello() {
            System.out.println("Son hello");
        }
    }
}
/*
Father hello
Son hello
*/

雖然常量池中的符號引用相同,invokevirtual指令最終指向的方法卻不一樣

分析invokevirtual指令搞懂它是如何確定調用的方法

1.invokevirtual找到棧頂元素的實際類型

2.如果在這個實際類型中找到與常量池中描述符與簡單名稱相符的方法,并通過訪問權限的驗證就返回這個方法的引用(未通過權限驗證返回IllegalAccessException非法訪問異常)

3.如果在實際類型中未找到,就去實際類型的父類中尋找(沒找到拋出AbstractMethodError異常)

因此,子類重寫父類方法時,根據(jù)invokevirtual指令規(guī)則,先找實際類型,所以才存在重寫的多態(tài)

頻繁的動態(tài)分派會重新查找棧頂元素實際類型,會影響執(zhí)行效率

為提高性能,JVM在該類方法區(qū)建立虛方法表使用索引表來代替查找

字段不存在多態(tài)

當子類出現(xiàn)與父類相同的字段,子類會覆蓋父類的字段

public class DynamicDispatch {
    public static void main(String[] args) {
        Father son = new Son();
    }
    static class Father{
        int num = 1;

        public Father() {
            hello();
        }

        public void hello(){
            System.out.println("Father hello " + num);
        }
    }

    static class Son extends Father{
        int num = 2;

        public Son() {
            hello();
        }

        @Override
        public void hello() {
            System.out.println("Son hello "+ num);
        }
    }
}
/*
Son hello 0
Son hello 2
*/

先對父類進行初始化,所以會先執(zhí)行父類中的構造方法,而構造方法去執(zhí)行了hello()方法,此時的實際類型是Son于是會去執(zhí)行Son的hello方法,此時子類還未初始化成員變量,只是有個默認值,所以輸出Son hello 0

八、單分派與多分派

public class DynamicDispatch {
    public static void main(String[] args) {
        Father son = new Son();
        Father father = new Father();

        son.hello(new Nod());
        father.hello(new Wave());
    }
    static class Father{


        public void hello(Nod nod){
            System.out.println("Father nod hello " );
        }

        public void hello(Wave wave){
            System.out.println("Father wave hello " );
        }
    }

    static class Son extends Father{

        @Override
        public void hello(Nod nod) {
            System.out.println("Son nod hello");
        }

        @Override
        public void hello(Wave wave) {
            System.out.println("Son wave hello");
        }
    }

    //招手
    static class Wave{}
    //點頭
    static class Nod{}
}
/*
Son nod hello
Father wave hello 
*/

宗量: 方法參數(shù)與方法調用者

分派還可以分為單,多分派

單分派:根據(jù)一個宗量選擇方法

多分派:根據(jù)多個宗量選擇方法

在編譯時,不僅要關心靜態(tài)類型是Father還是Son,還要關心參數(shù)是Nod還是Wave,所以靜態(tài)分派是多分派(根據(jù)兩個宗量對方法進行選擇)

在執(zhí)行son.hello(new Nod())時只需要關心實際類型是Son還是Father,所以動態(tài)分派是單分派(根據(jù)一個宗量對方法進行選擇)

到此這篇關于Java如何對方法進行調用詳解的文章就介紹到這了,更多相關Java調用方法內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java多線程中的Callable和Future詳解

    Java多線程中的Callable和Future詳解

    這篇文章主要介紹了Java多線程中的Callable和Future詳解,創(chuàng)建線程的兩種方式,一種是直接繼承Thread,另外一種就是實現(xiàn)Runnable接口,本文提供了部分代碼,需要的朋友可以參考下
    2023-08-08
  • mybatis 加載配置文件的方法(兩種方式)

    mybatis 加載配置文件的方法(兩種方式)

    這篇文章主要介紹了mybatis 加載配置文件的方法,通過實例代碼給大家介紹了mybatis 加載配置文件的兩種方式,需要的朋友可以參考下
    2017-12-12
  • gson對象序列化的示例

    gson對象序列化的示例

    本文介紹如何將Java對象序列化為Json文件,然后讀取該Json文件讀取回Java對象。在下面的示例中,我們創(chuàng)建了一個Student類。然后生成一個student.json文件,該文件將具有Student對象的json數(shù)據(jù)。
    2020-11-11
  • SpringBoot引入swagger報錯處理的解決方法

    SpringBoot引入swagger報錯處理的解決方法

    這篇文章主要給大家介紹SpringBoot引入swagger是會出現(xiàn)報錯的處理解決方法,文中有詳細的解決過程,感興趣的小伙伴可以跟著小編一起來學習吧
    2023-06-06
  • java使用ZipInputStream實現(xiàn)讀取和寫入zip文件

    java使用ZipInputStream實現(xiàn)讀取和寫入zip文件

    zip文檔可以以壓縮格式存儲一個或多個文件,本文主要為大家詳細介紹了java如何使用ZipInputStream讀取Zip文檔與寫入,需要的小伙伴可以參考下
    2023-11-11
  • Java實現(xiàn)二叉樹的深度優(yōu)先遍歷和廣度優(yōu)先遍歷算法示例

    Java實現(xiàn)二叉樹的深度優(yōu)先遍歷和廣度優(yōu)先遍歷算法示例

    這篇文章主要介紹了Java實現(xiàn)二叉樹的深度優(yōu)先遍歷和廣度優(yōu)先遍歷算法,結合實例形式詳細分析了二叉樹的定義、深度優(yōu)先遍歷與廣度優(yōu)先遍歷算法原理與相關操作實現(xiàn)技巧,需要的朋友可以參考下
    2018-04-04
  • springboot2.1.7整合thymeleaf代碼實例

    springboot2.1.7整合thymeleaf代碼實例

    這篇文章主要介紹了springboot2.1.7整合thymeleaf代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-12-12
  • spring源碼下載、編譯、debug的詳細教程

    spring源碼下載、編譯、debug的詳細教程

    這篇文章主要介紹了spring源碼下載、編譯、debug的詳細教程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-10-10
  • Spring Cloud Alibaba Nacos Config進階使用

    Spring Cloud Alibaba Nacos Config進階使用

    這篇文章主要介紹了Spring Cloud Alibaba Nacos Config進階使用,文中使用企業(yè)案例,圖文并茂的展示了Nacos Config的使用,感興趣的小伙伴可以看一看
    2021-08-08
  • springboot熱部署知識點總結

    springboot熱部署知識點總結

    在本篇文章里小編給大家整理了關于springboot熱部署的知識點內容,有興趣的朋友們參考學習下。
    2019-06-06

最新評論