2013-01-31 122 views
3

我有以下代碼:靜態VS動態綁定邏輯

import java.lang.*; 

public class Program 
{ 
    public static void main(String [] args) 
    { 
     B a = new A(); 

     a.p(10); 
     a.p(10.0); 
    } 
} 
    class B { 
     public void p(double i) 
     { 
      System.out.println(i*2); 
     } 
    } 

    class A extends B{ 
     public void p(int i) 
     { 
      System.out.println(i); 
     } 
    } 

當我執行使用B a = new A()這個代碼,我得到了這兩種情況下這是有意義的,因爲重載是在編譯時編譯器在哪裏看手柄20.0聲明的類型並適當調用一個函數。由於我們聲明的類型是B類,所以在這兩種情況下都調用B類的方法。現在如果我做A a = new A();,我應該在兩個答案中得到10,但我不是。我得到a.p(10)爲10,對於a.p(10.0)爲20.0。基於靜態綁定的概念和通過靜態綁定完成重載的整體概念,該靜態綁定將查看聲明的類型而不是實際的類型,爲什麼結果會以這種方式出現?我非常感謝你的幫助。

回答

1

在你的情況下,你正在做的重載將在編譯時綁定(靜態綁定。)。靜態綁定發生在引用類型而不是引用指向的對象類型。 在第一種情況下,您正在使用B的引用變量並將A的對象分配給它。由於引用是B,因此即使使用int,來自B的方法p(double)也會靜態綁定(因爲int can被擴大到雙倍)。在這種情況下,你有兩個p()方法可用。一個是來自B的p(雙)和來自A.So的其他p(int)p(10) )將調用p(int)和p(10.0)將調用p(雙)

試試這個:

class B { 
    public void p(String i) 
    { 
     System.out.println("parent:"+i); 
    } 
} 

class A extends B{ 
    public void p(int i) 
    { 
     System.out.println(i); 
    } 
} 
public class Test1 { 
    public static void main(String args[]) { 

     A a = new A(); //arg 
      a.p(10); 
      a.p("sample"); 
    } 
} 

如果你改變了行標ARG到B A =新的A(),你會看到編譯器試圖在這兩種情況下調用父p。

+0

如果你說的是正確的,那麼如果我改變我的子類方法public void p(double i){System.out(i * 3);},然後如果我調用B a = new A(),I在兩種情況下都應該達到20.0,但爲什麼我要達到30.0?編譯器爲什麼要查看子類方法?我會感謝你的幫助。 – Stranger

+1

在這種情況下,您重寫了動態綁定函數。在動態綁定的情況下,它的對象類型不是引用,它決定了在運行時調用哪個方法。因此,在這種情況下,您的方法調用都會調用子類中的過度使用方法。現在很明顯。 – Renjith

+0

啊!你是我的朋友。你說對了。非常感謝答案。你們好棒!! – Stranger

2

int可以擴大到double,但不是相反。這意味着10可以調用B.p(double)A.p(int),但10.0double,並且不會隱式轉換爲int,即只會調用B.p(double)

+0

感謝您的回答彼得 – Stranger

2

它,因爲你的方法p不是一個重寫的方法,它只是inhereted在當您使用

Super sup = new Sub(); 
sup.p(int); 
sup.p(double); 

在這種情況下,你的超類的子類有采用雙作爲參數的方法和一個int可以適合 a double您的超級類的方法被引用一個接受雙。

Sub sup = new Sub(); 
sup.p(int); 
sup.p(double); 

然而,在這種情況下,你的子類不具有采用了一倍,爲sup.p(double) call它使用了繼承的方法從超類,如果您雙擊作爲參數傳遞的方法。

1

當您編寫A a = new A()時,將創建一個類型爲A的新對象,該對象將有2個方法。 A.p(int)B.p(double),並且當您撥打A.p(10.0)時,由於缺乏轉換,它將調用B.p(double)

+0

感謝阿什溫在前面回答 – Stranger

+0

你歡迎,陌生人。我希望我很清楚。 – Achrome

1

這個反例可以幫助:

import java.lang.*; 

public class X 
{ 
    public static void main(String [] args) 
    { 
     B c = new A(); 

     c.p(10); 
     c.p(10.0); 
     c.p("AAA"); 
     ((A)c).p(10); 
    } 
} 
    class B { 
     public void p(String s) 
     { 
      System.out.println("B: my string is " + s); 
     } 

     public void p(double i) 
     { 
      System.out.println("B: twice my double is: " + i*2); 
     } 
    } 

    class A extends B{ 
     public void p(int i) 
     { 
      System.out.println("A: my number is " + i); 
     } 
    } 

輸出:

C:\temp>java X 
B: twice my double is: 20.0 
B: twice my double is: 20.0 
B: my string is AAA 
A: my number is 10 

的問題是:

1)你聲明類型爲 「B」(而不是「 A「)

2)Bp(10)可以接受int作爲浮點點參數

3)因此,這是你在說什麼

這真的是參數類型的問題,可以隱式轉換,比什麼方法被重載或覆蓋。

+0

感謝您的回答。感謝您的時間 – Stranger

1

當對象已聲明的類型B,該double版本是用Java調用int,因爲它是與int參數兼容的,因爲是double一個亞型。

當對象被聲明爲A,它有兩個版本重載的方法p()

p(int arg); 
p(double arg); 

所以,當你傳遞一個int,第一個版本被拾取,因爲它更準確,而當你通過double第二個,因爲它是最具體的簽名。

僅供參考,請參閱相關JLS at §15.12.2this post by Gilad Bracha。順便說一句,不要試圖根據你認爲最合乎邏輯的方式來理解語言應該如何表現,因爲每一種編程語言都是一項工程努力,這意味着你付出的任何代價都會付出代價。 Java的主要信息來源是JLS,如果仔細閱讀,您會(意外地發現)發現甚至有源代碼行不明確且無法編譯的情況。

+0

感謝您的回答。 – Stranger

0

爲了讓int的加寬效果更加生動,我創建了另一個值得一看的例子。在這裏,而不是double我創建了一個名爲Parent的類,而不是int a Child類已創建。

因此,
雙〜父
INT〜兒童

顯然子對象可以被加寬到父參考。

package test; 
public class OOPs { 
    public static void main(String[] args) { 
     Child ch = new Child(); // like int 10 
     Parent pa = new Parent();// like double 10.0 

     B a = new A(); // case 2 : A a = new A(); 

     a.p(ch);// 10 
     a.p(pa);// 10.0 
    } 
} 

class B { 
    public void p(Parent i) { 
     System.out.println("print like 20"); 
     System.out.println(i.getClass().getName()); 
    } 
} 

class A extends B { 
    public void p(Child i) { 
     System.out.println("print like 10"); 
     System.out.println(i.getClass().getName()); 
    } 
} 

class Parent { 
    String name; 

    Parent() { 
     name = "Parent"; 
    } 

    public String getName() { 
     return name; 
    } 
} 

class Child extends Parent { 
    String name; 

    Child() { 
     name = "Child"; 
    } 

    public String getName() { 
     return name; 
    } 
} 

案例1 - 輸出(B a = new A();)
打印像20
test.Child
打印像20
測試。家長

案例2 - 輸出(A a = new A();)
打印像10
test.Child
打印像20
test.Parent