簡體   English   中英

Java靜態和動態綁定,上載,重載混合在一起

[英]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() ,因為它在編譯時被確定為更特定,並且編譯器看到objSuperA類型的實例。 現在將objSuubB並調用test(obj2)

((SubB)obj).test(obj2); // cast to SubB

並顯示: "subclass's test() is called"表示它調用SubBtest(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方法調用。 因此,對於第二個示例,其中objobj2都使用SuperA類型SuperA :我們將需要將它們都SubB轉換為SubB才能調用SubBtest方法。

因為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM