一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - Java中的靜態綁定和動態綁定詳細介紹

Java中的靜態綁定和動態綁定詳細介紹

2019-12-08 21:16junie JAVA教程

這篇文章主要介紹了Java中的靜態綁定和動態綁定詳細介紹,在Java中存在兩種綁定方式,一種為靜態綁定,又稱作早期綁定,另一種就是動態綁定,亦稱為后期綁定,需要的朋友可以參考下

一個Java程序的執行要經過編譯和執行(解釋)這兩個步驟,同時Java又是面向對象的編程語言。當子類和父類存在同一個方法,子類重寫了父類的方法,程序在運行時調用方法是調用父類的方法還是子類的重寫方法呢,這應該是我們在初學Java時遇到的問題。這里首先我們將確定這種調用何種方法實現或者變量的操作叫做綁定。

在Java中存在兩種綁定方式,一種為靜態綁定,又稱作早期綁定。另一種就是動態綁定,亦稱為后期綁定。

區別對比

1.靜態綁定發生在編譯時期,動態綁定發生在運行時
2.使用private或static或final修飾的變量或者方法,使用靜態綁定。而虛方法(可以被子類重寫的方法)則會根據運行時的對象進行動態綁定。
3.靜態綁定使用類信息來完成,而動態綁定則需要使用對象信息來完成。
4.重載(Overload)的方法使用靜態綁定完成,而重寫(Override)的方法則使用動態綁定完成。

重載方法的示例

這里展示一個重載方法的示例。

 

復制代碼代碼如下:


public class TestMain {
  public static void main(String[] args) {
      String str = new String();
      Caller caller = new Caller();
      caller.call(str);
  }

 

  static class Caller {
      public void call(Object obj) {
          System.out.println("an Object instance in Caller");
      }
      
      public void call(String str) {
          System.out.println("a String instance in in Caller");
      }
  }
}

 

執行的結果為

 

復制代碼代碼如下:

22:19 $ java TestMain
a String instance in in Caller

 

在上面的代碼中,call方法存在兩個重載的實現,一個是接收Object類型的對象作為參數,另一個則是接收String類型的對象作為參數。str是一個String對象,所有接收String類型參數的call方法會被調用。而這里的綁定就是在編譯時期根據參數類型進行的靜態綁定。

驗證

光看表象無法證明是進行了靜態綁定,使用javap發編譯一下即可驗證。

 

復制代碼代碼如下:


22:19 $ javap -c TestMain
Compiled from "TestMain.java"
public class TestMain {
  public TestMain();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

 

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class java/lang/String
       3: dup
       4: invokespecial #3                  // Method java/lang/String."<init>":()V
       7: astore_1
       8: new           #4                  // class TestMain$Caller
      11: dup
      12: invokespecial #5                  // Method TestMain$Caller."<init>":()V
      15: astore_2
      16: aload_2
      17: aload_1
      18: invokevirtual #6                  // Method TestMain$Caller.call:(Ljava/lang/String;)V
      21: return
}

 

看到了這一行18: invokevirtual #6 // Method TestMain$Caller.call:(Ljava/lang/String;)V確實是發生了靜態綁定,確定了調用了接收String對象作為參數的caller方法。

重寫方法的示例

 

復制代碼代碼如下:

public class TestMain {
  public static void main(String[] args) {
      String str = new String();
      Caller caller = new SubCaller();
      caller.call(str);
  }
  
  static class Caller {
      public void call(String str) {
          System.out.println("a String instance in Caller");
      }
  }
  
  static class SubCaller extends Caller {
      @Override
      public void call(String str) {
          System.out.println("a String instance in SubCaller");
      }
  }
}

 

執行的結果為

 

復制代碼代碼如下:

22:27 $ java TestMain
a String instance in SubCaller

 

上面的代碼,Caller中有一個call方法的實現,SubCaller繼承Caller,并且重寫了call方法的實現。我們聲明了一個Caller類型的變量callerSub,但是這個變量指向的時一個SubCaller的對象。根據結果可以看出,其調用了SubCaller的call方法實現,而非Caller的call方法。這一結果的產生的原因是因為在運行時發生了動態綁定,在綁定過程中需要確定調用哪個版本的call方法實現。

驗證

使用javap不能直接驗證動態綁定,然后如果證明沒有進行靜態綁定,那么就說明進行了動態綁定。

 

復制代碼代碼如下:


22:27 $ javap -c TestMain
Compiled from "TestMain.java"
public class TestMain {
  public TestMain();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

 

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class java/lang/String
       3: dup
       4: invokespecial #3                  // Method java/lang/String."<init>":()V
       7: astore_1
       8: new           #4                  // class TestMain$SubCaller
      11: dup
      12: invokespecial #5                  // Method TestMain$SubCaller."<init>":()V
      15: astore_2
      16: aload_2
      17: aload_1
      18: invokevirtual #6                  // Method TestMain$Caller.call:(Ljava/lang/String;)V
      21: return
}

 

正如上面的結果,18: invokevirtual #6 // Method TestMain$Caller.call:(Ljava/lang/String;)V這里是TestMain$Caller.call而非TestMain$SubCaller.call,因為編譯期無法確定調用子類還是父類的實現,所以只能丟給運行時的動態綁定來處理。

當重載遇上重寫

下面的例子有點變態哈,Caller類中存在call方法的兩種重載,更復雜的是SubCaller集成Caller并且重寫了這兩個方法。其實這種情況是上面兩種情況的復合情況。

下面的代碼首先會發生靜態綁定,確定調用參數為String對象的call方法,然后在運行時進行動態綁定確定執行子類還是父類的call實現。

 

復制代碼代碼如下:

public class TestMain {
  public static void main(String[] args) {
      String str = new String();
      Caller callerSub = new SubCaller();
      callerSub.call(str);
  }
  
  static class Caller {
      public void call(Object obj) {
          System.out.println("an Object instance in Caller");
      }
      
      public void call(String str) {
          System.out.println("a String instance in in Caller");
      }
  }
  
  static class SubCaller extends Caller {
      @Override
      public void call(Object obj) {
          System.out.println("an Object instance in SubCaller");
      }
      
      @Override
      public void call(String str) {
          System.out.println("a String instance in in SubCaller");
      }
  }
}

 

執行結果為

 

復制代碼代碼如下:

22:30 $ java TestMain
a String instance in in SubCaller

 

驗證

由于上面已經介紹,這里只貼一下反編譯結果啦

 

復制代碼代碼如下:


22:30 $ javap -c TestMain
Compiled from "TestMain.java"
public class TestMain {
  public TestMain();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

 

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class java/lang/String
       3: dup
       4: invokespecial #3                  // Method java/lang/String."<init>":()V
       7: astore_1
       8: new           #4                  // class TestMain$SubCaller
      11: dup
      12: invokespecial #5                  // Method TestMain$SubCaller."<init>":()V
      15: astore_2
      16: aload_2
      17: aload_1
      18: invokevirtual #6                  // Method TestMain$Caller.call:(Ljava/lang/String;)V
      21: return
}

 

好奇問題

非動態綁定不可么?

其實理論上,某些方法的綁定也可以由靜態綁定實現。比如:

復制代碼代碼如下:

public static void main(String[] args) {
      String str = new String();
      final Caller callerSub = new SubCaller();
      callerSub.call(str);
}

 

比如這里callerSub持有subCaller的對象并且callerSub變量為final,立即執行了call方法,編譯器理論上通過足夠的分析代碼,是可以知道應該調用SubCaller的call方法。

但是為什么沒有進行靜態綁定呢?
假設我們的Caller繼承自某一個框架的BaseCaller類,其實現了call方法,而BaseCaller繼承自SuperCaller。SuperCaller中對call方法也進行了實現。

假設某框架1.0中的BaseCaller和SuperCaller

 

復制代碼代碼如下:

static class SuperCaller {
  public void call(Object obj) {
      System.out.println("an Object instance in SuperCaller");
  }
}
  
static class BaseCaller extends SuperCaller {
  public void call(Object obj) {
      System.out.println("an Object instance in BaseCaller");
  }
}

 

而我們使用框架1.0進行了這樣的實現。Caller繼承自BaseCaller,并且調用了super.call方法。

 

復制代碼代碼如下:

public class TestMain {
  public static void main(String[] args) {
      Object obj = new Object();
      SuperCaller callerSub = new SubCaller();
      callerSub.call(obj);
  }
  
  static class Caller extends BaseCaller{
      public void call(Object obj) {
          System.out.println("an Object instance in Caller");
          super.call(obj);
      }
      
      public void call(String str) {
          System.out.println("a String instance in in Caller");
      }
  }
  
  static class SubCaller extends Caller {
      @Override
      public void call(Object obj) {
          System.out.println("an Object instance in SubCaller");
      }
      
      @Override
      public void call(String str) {
          System.out.println("a String instance in in SubCaller");
      }
  }
}

 

然后我們基于這個框架的1.0版編譯出來了class文件,假設靜態綁定可以確定上面Caller的super.call為BaseCaller.call實現。

然后我們再次假設這個框架1.1版本中BaseCaller不重寫SuperCaller的call方法,那么上面的假設可以靜態綁定的call實現在1.1版本就會出現問題,因為在1.1版本上super.call應該是使用SuperCall的call方法實現,而非假設使用靜態綁定確定的BaseCaller的call方法實現。

所以,有些實際可以靜態綁定的,考慮到安全和一致性,就索性都進行了動態綁定。

得到的優化啟示?

由于動態綁定需要在運行時確定執行哪個版本的方法實現或者變量,比起靜態綁定起來要耗時。

所以在不影響整體設計,我們可以考慮將方法或者變量使用private,static或者final進行修飾。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产清纯白嫩大学生正在播放 | 日本高清在线看 | 国产一区二区在线观看视频 | 国产乱码一卡二卡3卡四卡 国产乱插 | 91在线 一区 二区三区 | 九九热在线免费观看 | 成年人福利视频 | 日产中文乱码卡一卡二 | 日本伊人久久 | 草女人逼| 日本特黄一级午夜剧场毛片 | 99国产精品免费视频 | 亚洲国产午夜看片 | 手机跑分排行最新排名 | 美日毛片 | 久久三级网站 | 青青热久免费精品视频网站 | 亚洲国产果果在线播放在线 | 青青草原国产一区二区 | 免费精品99久久国产综合精品 | 欧美成狂野欧美在线观看 | 久久日本片精品AAAAA国产 | 亚洲精品无码不卡 | 亚洲成人视屏 | 国产激情一区二区三区成人91 | 韩国三级年轻的小婊孑 | 国产区一二三四区2021 | 99青青青精品视频在线 | 国产精品一区二区不卡的视频 | 国产一级毛片国语版 | 天天av天天翘天天综合网 | 国产3p在线 | 亚洲精品91大神在线观看 | 欧亚专线欧洲m码可遇不可求 | 无码中文字幕热热久久 | 九九99在线视频 | 国内自拍网红在线综合 | 性做久久久久久久久老女人 | 视频在线观看国产 | 春意午夜影院 | 亚洲精彩视频在线观看 |