2016-03-27 45 views
23

我試圖從double在外殼上取下fractional部分是整個使用:爪哇 - 三元操作怪異的行爲

(d % 1) == 0 ? d.intValue() : d 

和遇到下列行爲,我不明白:

public static void main(String[] args) { 
    Double d = 5D; 
    System.out.println((d % 1) == 0);        // true 
    System.out.println((d % 1) == 0 ? d.intValue() : "not whole"); // 5 
    System.out.println((d % 1) == 0 ? d.intValue() : d);   // 5.0 
} 

正如您在第三行看到的那樣,即使滿足條件(d % 1) == 0,操作員也會選擇else的值 - 5.0

這是怎麼回事?

+3

它在這兩種情況下都選擇'd.intValue()',它只是執行轉換以確保第二個和第三個參數具有相同的類型。 – Keppil

+0

可能被認爲是http://stackoverflow.com/questions/8002603/why-does-the-ternary-operator-unexpectedly-cast-integers(及其所有重複項)的副本... – Marco13

+0

@ Marco13,我是在發佈問題時不知道投射是問題。也許這是事後的重複.. – Daniel

回答

35

三元條件運算符的返回類型必須是第二個和第三個操作數都可以分配給它。

因此,在第二種情況下,運營商的返回類型爲Object(因爲這兩個d.intValue()"not whole"必須分配給它),而在第三個案例是Double(因爲這兩個d.intValue()d必須分配給它)。

打印的Object運行時類型爲Integer給你5在打印Double給你5.0

+0

但是,爲什麼當它們都可以分配給一個String時,它被轉換爲'Object'而不是'String'? – Daniel

+3

@Daniel實際上,'Integer'不能被分配給一個'String',它必須先被轉換爲一個String(例如,通過使用'Integer'的'toString')。它只在您的示例中轉換爲字符串以便由println打印。 – Eran

3

它選擇正確。然後它包裝成雙。這些是3個關鍵點:

  1. 如果第二個和第三個操作數具有相同的類型,那就是條件表達式的類型。換句話說,你可以通過避免混合類型的計算來避免整個混亂。

  2. 如果其中一個操作數的類型爲T,其中T爲byte,short或char,另一個操作數爲類型爲int的常量表達式,其值可用T類型表示,則條件表達式的類型爲T

  3. 否則,對操作數類型應用二進制數字提升,並且條件表達式的類型是第二個和第三個操作數的提升類型。

11

表達式a ? b : c的類型總是與c或最接近的共同父親bc相同。

System.out.println((d % 1) == 0 ? d.intValue() : "not whole"); // Comparable a parent of Integer and String 
System.out.println((d % 1) == 0 ? d.intValue() : d);   // Double is a widened int 

BTW d % 1將只檢查它是一個整體不,不,它是足夠小,適合在一個int值。一個更安全的檢查,看是否強制轉換爲intlong

時,也可以阻止它擴大long回雙帶

double d = 5.0; 
System.out.println((long) d == d ? Long.toString((long) d) : Double.toString(d)); 
+1

謝謝,在我的情況下(數字代表csat),最大可能值是5,所以生活的感謝比這更簡單.. – Daniel

1

在你的情況下,值是相同的ternery運算符的第二個和第三個參數是類型「int」和「Double」。 Java必須將這些值轉換爲相同的類型,以便它們可以從三元運算符返回。Java語言規範給出了這樣做的規則。 https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25

在你的情況下,這些規則導致兩個參數轉換爲類型「double」(「Double」被解開,int被值轉換)。

解決的辦法是將參數強制轉換爲三元運算符,以使它們具有相同的類型(在下面可能會有更多的括號比嚴格需要,我對java運算符優先規則有點生疏)。

System.out.println((d % 1) == 0 ? ((Number)(d.intValue())) : (Number)d);