[英]Java static and dynamic binding, upcast, overloading mixed together
假設我們有以下代碼
class TestEqual{
public boolean equals(TestEqual other ) {
System.out.println( "In equals from TestEqual" ); return false;
}
public static void main( String [] args ) {
Object t1 = new TestEqual(), t2 = new TestEqual();
TestEqual t3 = new TestEqual();
Object o1 = new Object();
int count = 0;
System.out.println( count++ );// shows 0
t1.equals( t2 ) ;
System.out.println( count++ );// shows 1
t1.equals( t3 );
System.out.println( count++ );// shows 2
t3.equals( o1 );
System.out.println( count++ );// shows 3
t3.equals(t3);
System.out.println( count++ );// shows 4
t3.equals(t2);
}
}
基本上,在TestEqual類(當然是擴展Object的類)中,我們有一個方法從Object重載equals方法。
此外,我們還有一些變量:對象t1,t2實例為TestEqual,TestEqual t3實例為TestEqual和對象o1實例為對象。
如果我們運行程序,則將是輸出。
0
1
2
3
In equals from TestEqual
4
這個例子似乎比通常的Car c = new Vehicle()更復雜。 c.drive(); 因為我們調用該方法的對象的實例與其類型不同,並且該方法的參數的實例也與其類型不同。
我想檢查一下我是否正確理解了在調用每種方法時會發生什么情況(有關綁定的分步說明)。
show 0
t1.equals(t2)
show 1
t1被視為TestEqual對象。 equals方法重載,因此綁定是靜態的,這意味着我們將t2作為Object傳遞,因此它將調用從Object超類繼承的equals方法,因此不會顯示任何文本。
show 1
t1.equals(t3)
show 2
這似乎有點不可思議。 我本來希望顯示“來自TestEqual的等於”,因為t3是一個TestEqual對象,所以應該調用來自t1的等於。 我在這里的解釋是t1是靜態綁定的並且被視為Object,因此稱為從Object類繼承的equals方法被調用,參數TestEqual t3被向上轉換為Object。 但這是否意味着從t1.equals(t2)開始的先前解釋是錯誤的?
show 2
t3.equals(o1);
show 3
t3是一個TestEqual對象,參數o1是一個Object,因此調用了從Object繼承的equals方法,因此不打印任何內容。
show 3
t3.equals(t3)
show 4
t3是一個TestEqual對象,該參數是一個TestEqual對象,因此將調用TestEqual中的重載方法,並打印“ In from equals TestEqual”。
show 4
t3.equals(t2)
t3是一個TestEqual對象,由於靜態綁定(重載方法),該參數是一個Object,因此調用了從Object繼承的equal方法,不打印任何內容。
方法Object.equals(Object obj)將另一個Object
實例作為參數。 如果您將TestEqual
定義為:
class TestEqual{
@override
public boolean equals(Object other ) {
System.out.println( "In equals from TestEqual" ); return false;
}
}
它會按您期望的那樣工作。
這似乎有點不可思議。 我本來希望顯示“來自TestEqual的等於”,因為t3是一個TestEqual對象,所以應該調用來自t1的等於。 我在這里的解釋是t1是靜態綁定的並且被視為Object,因此稱為從Object類繼承的equals方法被調用,參數TestEqual t3被向上轉換為Object。 但這是否意味着從t1.equals(t2)開始的先前解釋是錯誤的?
要在重載的情況下調用方法,會發生最具體的方法調用,並在編譯時確定。 選擇最特定方法的規則在Java語言規范15.12.2.5中定義。 選擇最具體的方法 :在其他討論中,提到的陳述是:
當且僅當m1比m2更特定且m2不比m1更具體時,方法m1才比另一方法m2嚴格更具體。
為了解釋您的上下文,但是讓我們聲明兩個簡單的Super類和sup類:
class SuperA
{
public void test(SuperA a)
{
System.out.println("super class's test() is called");
}
}
class SubB extends SuperA
{
public void test(SubB subB)
{
System.out.println("subclass's test() is called");
}
}
現在,如果我們以這種方式創建兩個實例:
SuperA obj = new SubB();
SubB obj2 = new SubB();
obj.test(obj2);
您將看到調用了超類的test()
,因為它在編譯時被確定為更特定,並且編譯器看到obj
是SuperA
類型的實例。 現在將obj
為SuubB
並調用test(obj2)
:
((SubB)obj).test(obj2); // cast to SubB
並顯示: "subclass's test() is called"
表示它調用SubB
的test(obj)
方法,因為這一次編譯器知道obj
具有SubB
的類型和最特定的調用test
分辨率。
但是,現在讓我們以這種方式聲明兩個實例:
SuperA obj = new SubB();
SuperA obj2 = new SubB();
obj.test(obj2); // invokes super class's test method
((SubB)obj).test(obj2);// invokes super class's test method
((SubB)obj).test((SubB)obj2); // invoke sub class's test method
在這一系列調用中,前兩個語句將調用超類SuperA
的測試方法,因為這些調用更為具體。 但是,要解釋第二種情況:
((SubB)obj).test(obj2);// invokes super class's test method
這次的編譯器知道obj
具有SubB
的類型,但仍然看到obj2
具有SperA
的類型,它更特定於test
方法調用。 因此,對於第二個示例,其中obj
和obj2
都使用SuperA
類型SuperA
:我們將需要將它們都SubB
轉換為SubB
才能調用SubB
的test
方法。
因為Object
是Java中所有類的超類,所以您現在應該了解,但是上下文的equal
方法調用系統。 為了避免這種調用陷阱,您將看到java類中所有實現的equal
方法實際上是equal
方法Object
類的替代 ,並使用了instanceof
檢查。 例如, Integer
類的equal方法實現:
public boolean equals(Object obj) {
if (obj instanceof Integer) { //<<<---- instance of checking
return value == ((Integer)obj).intValue();
}
return false;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.