2017-09-07 119 views
1

我想澄清一些關於綁定和調度的問題。靜態/動態綁定和靜態/動態調度有點令人困惑

綁定將方法調用附加到方法簽名。調度正在選擇方法實現。首先綁定,然後派遣。好的,我得到了這個,但是:

  1. 未被覆蓋的實例方法是否使用靜態綁定?
  2. 爲什麼重載方法使用靜態綁定,因爲它們是虛擬的,可以在子類中重寫?

我在過去的幾天裏看過很多的解釋,現在對我來說是一團糟。其中有些是互相沖突或完全相反的。從我知道的所有非static,非private和非final在Java中的方法默認是虛擬的,並且必須使用動態綁定和動態分派。

+0

1號堂妹可能被別人取代。編譯器不會知道一個方法沒有被覆蓋。例外是私有方法和最終方法,至少前者是靜態綁定的。 2.什麼讓你覺得「重載方法使用靜態綁定」? –

回答

1

綁定將方法調用附加到方法簽名。調度正在選擇方法實現。

綁定意義上的意思是指超載。在你的意思是指覆蓋的意義上調度。

先來綁定,然後發送。

是的。編譯器執行綁定,JVM進行分派。

OK,我得到了這一點,但:

  1. 難道還沒有被覆蓋使用靜態綁定實例的方法呢?

號編譯器不能告訴,除了在privatefinal方法的情況。

  • 爲什麼究竟重載方法使用靜態綁定,因爲它們是虛擬並且可以在子類覆蓋?
  • 他們沒有。

    從我所知道的所有非靜態,非私有和非最終的Java方法在默認情況下都是虛擬的,並且必須使用動態綁定和動態分派。

    正確。

    +0

    現在我明白重載的方法是虛擬的,它在運行時使用動態綁定,但是:3)重載方法使用靜態綁定綁定,而重寫的方法在運行時使用動態綁定綁定。這是什麼意思? –

    +0

    @violet_eyes我見過這樣的說法:「重載的方法使用靜態綁定綁定,而重寫的方法在運行時使用動態綁定綁定」。在很少的博客上,但這種說法並不總是正確的。這完全取決於方法被調用和聲明的方式。你可以看到我在答案中提供的案例,重載方法是動態綁定的。 –

    +0

    這部分看起來不對:_No。除了private或final方法外,編譯器不能說明這一點._只有一個字節碼:'invokevirtual'在編譯時調用非靜態非接口方法,即使是'private/final'方法,所以編譯時的行爲是一樣的。在運行時編譯(JIT)期間,'final'和'private'也不會幫助任何現代JVM確定是否存在重寫方法,無論是否存在final或private。所以在實踐中,這些限定符不會改變編譯或運行時的行爲。 – BeeOnRope

    0

    規則對Java綁定:

    1)調用一個靜態方法是靜態綁定。

    2)調用構造函數是靜態綁定的。

    3)呼叫,以非靜態方法是動態綁定:

    例外: 3.A)調用私有的,非靜態方法是靜態綁定。

    3.b)在子類中調用使用super的非私有非靜態方法也是靜態綁定的。

    因此對於第一個問題即沒有被覆蓋的實例方法是否使用靜態綁定?

    答案是No.如果該方法沒有被覆蓋,但它可以(將來)。因爲它是一個實例方法,所以它可以使用實例(動態綁定)或使用超級(靜態綁定)調用。

    第二個問題:爲什麼重載方法使用靜態綁定,因爲它們是虛擬的,可以在子類中重寫?

    答案:沒有這樣的事情,重載的方法是靜態綁定的。

    說明:

    class Sample{ 
    
        public void method1(){ 
         System.out.println("hello from A"); 
        } 
    
        public void method1(String user){ 
         System.out.println("hello "+user+" from overloaded method"); 
        } 
    
         public static void main(String []argh){ 
         Sample s = new Sample(); 
         s.method1(); 
         s.method1("name"); 
        } 
    } 
    

    在上面的代碼中,該方法method1()過載,但因爲它既不是靜態的,最終也不私有的,所以它產生invokevirtual指令,這意味着它被動態地綁定不是靜態的。

    要清除的結合的差異,調度是指這個Question

    +1

    'final'方法在編譯時不是靜態綁定的。試試這個[實驗](https://gist.github.com/travisdowns/92e85659cc9680df82fb0b9a98e11193)。把'Base','Derived'和'Print'放在自己的文件中,用'javac'編譯'Base'和'Print'。現在'Print.printBase'應該是_statically綁定到'Base.print()'的調用,因爲這個調用是'final'。將'Print.class'移到某處,然後從'Base.print()'中移除'final'修飾符。編譯'Derived'(這也將編譯'Base'和'Print',因爲'javac'編譯依賴關係 – BeeOnRope

    +0

    最後,拷貝最初編譯的'Print.class'版本'靜態綁定'版本(替換最新的)。在Derived中運行'main()',注意它打印出了''derived''。儘管打印是在最後的Base.print()中編譯的,但是沒有靜態綁定,你可以用'javap ' - 生成的字節碼使用'invokevirtual'來調用'print()' - 不管被調用的方法是final還是not_。事實上,這是用於調用非靜態非接口方法的_only_字節碼,所以不能在編譯的時候是靜態綁定的東西 – BeeOnRope

    +0

    以前我沒有在我的答案中寫'final',但後來有些書讓我困惑,在Java中,Complete引用它提到「由於final方法不能被覆蓋,一個調用可以在編譯時解決,這叫做早期綁定「,a另外,在「Thinking in Java」中,「Java中的所有方法綁定使用後期綁定,除非方法是靜態或最終的」 感謝您明確綁定不依賴於「final」。 –