亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

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

2019-11-26 15:18:57
字體:
來源:轉載
供稿:網友

一個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進行修飾。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
成人a视频在线观看| 黄网站色欧美视频| 国产精品久久久久久中文字| 欧美乱妇高清无乱码| 粉嫩老牛aⅴ一区二区三区| 97在线观看视频| 精品久久久久久久久久| 日韩亚洲成人av在线| 亚洲在线视频福利| 在线视频中文亚洲| 亚洲精品免费一区二区三区| 中文字幕日韩精品在线| 日韩欧美大尺度| 伊人久久大香线蕉av一区二区| 亚洲欧美中文日韩在线v日本| 91禁国产网站| 欧美成人精品一区二区| 久久久久久久影院| 亚洲香蕉av在线一区二区三区| 国产成人一区三区| 亚洲自拍小视频| 国产精品jvid在线观看蜜臀| 国产噜噜噜噜噜久久久久久久久| 91精品成人久久| 久久亚洲精品中文字幕冲田杏梨| 国产mv免费观看入口亚洲| 91高清在线免费观看| 欧美久久精品一级黑人c片| 69久久夜色精品国产7777| 国产精品久久久久久网站| 国产精品久久久久久久久久久久久| 国产成人在线亚洲欧美| 91社区国产高清| 538国产精品视频一区二区| 国内精品久久久久影院优| 国产欧美 在线欧美| 国产精品自产拍在线观看| 91精品国产777在线观看| 国产精品午夜国产小视频| 欧美亚洲另类视频| 欧美色视频日本高清在线观看| 国产亚洲视频在线观看| 欧美日韩国产综合视频在线观看中文| 国产日韩欧美成人| 久久久久久久999精品视频| 精品久久久久久久中文字幕| 久久九九免费视频| 热久久视久久精品18亚洲精品| 一区二区三区精品99久久| 亚洲日韩第一页| 欧美激情免费视频| 欧美在线观看日本一区| 国产精品1区2区在线观看| 欧美成人免费在线视频| 91免费视频国产| 性色av一区二区三区| 欧美乱妇40p| 国外成人在线直播| 国产成人久久久| 精品亚洲国产视频| 国产精品久久久久久久久| 日韩一区二区久久久| 一本大道香蕉久在线播放29| 亚洲国产精品小视频| 日本国产一区二区三区| 国产成人精品在线观看| 国产日产欧美a一级在线| 国产日韩欧美视频| 日韩视频―中文字幕| 5278欧美一区二区三区| 中文字幕国产亚洲2019| 欧美一级高清免费| 日韩中文在线不卡| 日韩免费观看av| 欧美性xxxxx极品娇小| 国产精品香蕉国产| 日韩电影中文字幕一区| 国产精品成人一区| 亚洲一区亚洲二区| 欧美在线亚洲一区| 亚洲精品一区二区三区不| 91精品视频在线播放| 91po在线观看91精品国产性色| 亚洲第一级黄色片| 尤物九九久久国产精品的分类| 国产精品成人免费电影| 国产精品第2页| 日韩精品中文字| 亚洲福利小视频| 国产精品成人av性教育| 国产亚洲一区二区精品| 俺也去精品视频在线观看| 国产精品国模在线| 国产在线拍偷自揄拍精品| 欧洲成人性视频| 91高清在线免费观看| 国产日韩精品一区二区| 国产精品99久久久久久久久久久久| 久久影视电视剧凤归四时歌| 国产精品久久久久久中文字| 久久国产精品久久国产精品| 成人激情视频在线播放| 97视频在线观看网址| 亚洲国产日韩欧美综合久久| 国产一区二区日韩精品欧美精品| 国产精品欧美激情在线播放| 久久精品免费电影| 日韩欧美在线一区| 欧美电影免费观看网站| 久久亚洲影音av资源网| 亚洲免费视频一区二区| 国产精品福利网| 日韩av网站电影| 精品中文字幕在线观看| 日韩激情av在线免费观看| 色综合视频一区中文字幕| 欧美黑人巨大精品一区二区| 亚洲成人黄色在线观看| 米奇精品一区二区三区在线观看| 国产精品99久久久久久白浆小说| 北条麻妃久久精品| 欧美精品日韩三级| 亚洲人成绝费网站色www| 亚洲美女中文字幕| 欧美大片免费看| 国产精品丝袜久久久久久不卡| 日韩国产高清视频在线| 疯狂做受xxxx高潮欧美日本| 美女精品视频一区| 最近中文字幕mv在线一区二区三区四区| 91欧美日韩一区| 色99之美女主播在线视频| 性色av一区二区三区在线观看| 国内精品久久久久影院 日本资源| 91国产在线精品| 日韩最新中文字幕电影免费看| 日韩视频免费大全中文字幕| 国产精品久久久久久久久借妻| 一本一道久久a久久精品逆3p| 久久久亚洲网站| 136fldh精品导航福利| 久久久999国产| 国产综合久久久久久| 国产精品一区专区欧美日韩| 欧美综合在线第二页| 亚洲免费电影在线观看| 欧美精品电影在线| 欧美性资源免费| 精品欧美一区二区三区| 亚洲老头老太hd| 亚洲激情小视频| 久久99久久亚洲国产| 人体精品一二三区| 精品成人av一区| 国产999精品| 日本精品久久久久影院| 国产一区私人高清影院| 国产精品亚洲аv天堂网| 国产日韩欧美电影在线观看| 国产极品jizzhd欧美| 国产精品一区二区久久久久| 国产欧美一区二区三区久久人妖| 国产亚洲精品一区二555| 国产精品精品视频一区二区三区|