程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java中的靜態綁定和靜態綁定具體引見

Java中的靜態綁定和靜態綁定具體引見

編輯:關於JAVA

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停止潤飾。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved