簡體   English   中英

為什么靜態方法不涉及多態(后期綁定)我看到錯誤,靜態方法不能被覆蓋

[英]Why if static method don't involve in polymorphism(late binding) I see error that static method cannot be overridden

請考慮以下代碼:

class A{
    public static void m(Number n){
         System.out.println("Number A");
    };
}
class B extends A{
     public static int m(Number n){
        System.out.println("Number B");
        return 1;
      };
}

輸出:

java中的:inheritanceTest.B中的m(java.lang.Number)不能覆蓋inheritanceTest中的m(java.lang.Number)。返回類型int與void不兼容

我知道靜態方法不涉及多態,因此我推斷我的代碼不可能覆蓋。 這個編譯器消息對我來說很奇怪。

據我所知,重寫是多態的一部分。 我准備scjp,我害怕在熟悉的問題上犯錯誤。

請澄清這個問題。

我的預期行為 - 有關重載錯誤的消息

P.S1。

我已經閱讀了關於靜態覆蓋的最受歡迎的問題,我沒有找到答案(

P.S2。 據Pshemo回答:

這段代碼:

class Foo{
    public static void m(Number n){
         System.out.println("Number A");
    };
    public static int m(Number n){
        System.out.println("Number B");
        return 1;
    };
}

輸出:

error: method m(Number) is already defined in class Foo
    public static int m(Number n){
                      ^
1 error

對我來說,這些情況是一樣的。 但編譯器錯誤不同 - 很奇怪。

即使靜態方法無法被覆蓋,它們仍然是繼承的,所以你要做的事情會導致類似的情況

class Foo{
    public static void m(Number n){
         System.out.println("Number A");
    };
    public static int m(Number n){
        System.out.println("Number B");
        return 1;
    };
}

這是錯誤的,因為你不能有兩個具有相同簽名但具有不同返回類型的方法。 它被禁止的原因很簡單......讓我們說我們有方法:

  • Foo method(){ return new Foo(); }
  • Bar method(){ return new Bar(); }

你會想要像他們一樣調用它們

System.out.println(method());

結果應該是Foo還是Bar? 編譯器無法決定。

為了防止這種情況,編譯器通過更改其返回類型來禁止覆蓋/隱藏具有相同簽名的方法。 唯一的例外是當您將返回類型更改為更詳細的類型時

class X{
    List<String> m(){...}
}

class Y extends X{
    LinkedList<String> m(){...}
}

因此, override似乎不是最好的詞。 應該hide正確的單詞,因為靜態方法可以隱藏,而不是被覆蓋。 但它看起來像是相同的規則(或至少它們的一部分)用於測試我們是否可以將方法隱藏為覆蓋規則,因此在出現問題時會顯示相同的錯誤消息(關於覆蓋而不是隱藏),這可能是誤導。

JLS§8.4.8.3(Java 8)說:

如果一個方法聲明d 1與返回類型的R 1所 覆蓋或隱藏的另一方法d 2與返回類型中的R 2的聲明,則d 1必須返回型取代(§8.4.5)為d 2,或編譯發生時間錯誤。

同樣的規則同時適用於實例方法和靜態方法,因為它表示“覆蓋或隱藏”。 基本上,如果你有一個具有相同名稱和相同參數的方法,它會覆蓋它是一個實例方法,但如果它是一個類(靜態)方法則隱藏(繼承方法)。 在這兩種情況下,返回類型必須相同或遵守協方差規則。

由於它是相同的規則,很可能在編譯器代碼中只有一個地方檢查此規則,如果規則被違反,您將收到您正在看到的錯誤,我確信這是更常見的情況。 編譯器確實應該檢查是否應該說“覆蓋”或“隱藏”,但看起來它們會滑落。 完全正確地獲取錯誤消息通常不是編譯器編寫者的最高優先級 - 與確保編譯應該編譯的代碼並運行正確,而不應該編譯的代碼不相比。 所以我認為這是一個缺陷,但非常小。

我認為'覆蓋'的編譯器錯誤用法在這里有誤導性,它不適用。

語言規范說:

如果具有返回類型R1的方法聲明d1覆蓋或隱藏具有返回類型R2的另一個方法d2的聲明,則d1必須是d2的return-type substitutable,否則會發生編譯時錯誤。

這里你的B方法隱藏了Am的聲明:

如果一個類聲明了靜態方法m,則聲明m被稱為隱藏任何方法m',其中m的簽名是m'簽名的子簽名(第8.4.2節),在超類和超接口中。該類中的代碼可以訪問的類。

如果你的B類沒有m方法,那么你可以調用Bm,它會調用A上定義的m。

讓Bm隱藏A的m版本。 因為您可以調用在超類上定義的靜態方法但引用子類,這會設置對不同返回類型違反的方法的一些期望。

它隱藏而不是覆蓋,因為如果你定義了Bm,你仍然可以調用Am並獲得該方法的超類版本。 覆蓋它的運行時類型決定了被調用的內容以及它的調用方式並不重要。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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