簡體   English   中英

Java重載 - long和float

[英]Java overloading - long and float

我試圖了解java重載規則。 一切似乎都很好,除了以下,

public static void main(String[] args) {
    long aLong = 123L;        
    foo(aLong);
}

private static void foo(double aDouble) {
    System.out.println("Foo aDouble");
}

private static void foo(Long aWrapperLong) {
    System.out.println("Foo Wrapper Long");
}

private static void foo(int anInt) {
    System.out.println("Foo Int");
}

private static void foo(float aFloat) {
    System.out.println("Foo Float");
}

為什么調用解析為foo(float aFloat) 我從JLS了解以下內容,

此步驟使用方法的名稱和參數表達式的類型來定位可訪問和適用的方法可能有多個此類方法,在這種情況下,選擇最具體的方法。

我故意在這里使用Wrapper Long而不是原始的long。 原始長度為64位大小不會以foo(double aDouble)結束,而是32位float foo(float aFloat)

問題為什么Java隱式(沒有強制轉換)將`long`轉換為`float`? 進一步澄清了這個問題的答案。

這是因為JLS#15中的“最具體”規則又引用了JLS#4.10 ,后者又引用了#4.10.1,其中指出:

以下規則定義了基本類型之間的直接超類型關系:

  • double> 1 float

  • 漂浮> 1

  • 長> 1 int

  • int> 1個字符

  • int> 1

  • 短> 1個字節

其中“S> 1 T”表示“T是S的直接子類型”,根據本節緊接的JLS#4.10。

因此,在這種情況下,如果沒有long的直接匹配,並且在查看自動裝箱之前,編譯器會根據上述規則選擇最接近的可用超類型,即float

來自JLS的報價:

確定適用性的過程首先確定可能適用的方法(§15.12.2.1)。

該過程的其余部分分為三個階段,以確保與Java SE 5.0之前的Java編程語言版本兼容。 階段是:

  1. 第一階段(§15.12.2.2)執行重載解析而不允許裝箱或拆箱轉換,或使用變量arity方法調用。 如果在此階段沒有找到適用的方法,則處理繼續到第二階段。

這保證了在Java SE 5.0之前在Java編程語言中有效的任何調用都不會因為引入變量arity方法,隱式裝箱和/或取消裝箱而被認為是不明確的。 但是,變量arity方法(第8.4.1節)的聲明可以更改為給定方法方法調用表達式選擇的方法,因為變量arity方法在第一階段被視為固定arity方法。 例如,在已聲明m(Object)的類中聲明m(Object ...)會導致不再為某些調用表達式(例如m(null))選擇m(Object),因為m(Object [] )更具體。

  1. 第二階段(§15.12.2.3)執行重載解析,同時允許裝箱和拆箱,但仍然排除使用變量arity方法調用。 如果在此階段沒有找到適用的方法,則處理繼續到第三階段。 ...

編輯:關於選擇 float而不是double:

如果多個成員方法都可訪問並適用於方法調用,則必須選擇一個為運行時方法調度提供描述符。 Java編程語言使用選擇最具體方法的規則。

非正式的直覺是,如果第一個方法處理的任何調用都可以傳遞給另一個沒有編譯時錯誤的調用,那么一個方法比另一個方法更具體。

重載決策的第一階段將選擇這四種方法中的兩種

private static void foo(double aDouble) 
private static void foo(float aFloat) 

因為第一階段不允許裝箱/拆箱( Long ),並且你不能在沒有顯式鑄造的情況下使用int參數傳遞long方法。 將選擇最具體的方法。 在這種情況下, float方法將被解釋為最具體而不是double

轉換具有優先規則。 它將選擇擴大 拳擊

因此,在這種情況下,編譯器搜索的方法可以接受比長原始數據類型更大(最接近可能更大)的參數作為參數,即float。

如果從發布的示例中刪除方法foo(double aDouble)foo(float aFloat) ,則編譯器將執行裝箱並選擇foo(Long aWrapperLong)

在自動裝箱以進行重載之前,擴展優先。 原始的包裝類(Integer,Long等)從一開始就沒有在java中引入,因為java支持向后兼容性,它應該執行在較新版本中以相同方式在一個java版本中編寫的代碼。

暫無
暫無

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

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