2016-09-21 79 views
8

我很困惑,爲了讓這段代碼正常工作,我必須做些什麼。看起來好像編譯器優化了我需要的類型轉換,或者有其他我不明白的東西。編譯器刪除我的類型轉換?

我有各種對象存儲在數據庫中,實現接口Foo。我有一個對象,bar,它包含我用來檢索我的Foo對象的數據。 bar有這些方法:

Class getFooClass() 

Long getFooId() 

餘類和ID傳遞到與此簽名,冬眠其代表是根據它的類和ID以檢索對象的方法:

public <T> T get(Class<T> clazz, Serializable id); 

有不同Foo的實現者,其中一些休眠對象有一個Long ID,而其他的有一個Integer ID。儘管這種方法可以接受,但更進一步,最好有正確的方法。所以,當我試着打get()Integer ID的對象,如下所示,我可以理解得到一個錯誤的抱怨,我已經提供了其中的Integer是需要Long

get(bar.getFooClass(), bar.getFooId()); 

這裏有沒有休眠的問題,我只需要提供一個Integer,其中需要一個Integer id和一個Long,其中需要一個Long id。所以我增加了一個方法barhasLongId(),並嘗試這樣的:(在這一點上,你可能會想,這不是一個好的設計,但是這不是我的問題現在)

get(bar.getFooClass(), 
    bar.hasLongId() ? bar.getFooId() : bar.getFooId().intValue()); 

它仍然抱怨說,我提供了一個Long。這似乎很奇怪。然後我試過這個:

get(bar.getFooClass(), 
    bar.hasLongId() ? bar.getFooId() 
        : new Integer(bar.getFooId().intValue())); 

同樣的錯誤!怎麼會這樣?所以我在調試器中穿過,是的,它穿過intValue(),也穿過Integer構造函數,但是在get方法中,傳遞的參數實際上是從getFooId()返回的同一個Long對象。

我不明白髮生了什麼,所以我只是嘗試不同的東西:

Integer intId = bar.getFooId().intValue(); 
get(bar.getFooClass(), bar.hasLongId() ? bar.getFooId() : intId); 
// same error 

Serializable id = bar.hasLongId() ? bar.getFooId() 
           : new Integer(bar.getFooId().intValue()); 
get(bar.getFooClass(), id); 
// same error 

最後:

Serializable id; 
if (bar.hasLongId()) { 
    id = bar.getFooId(); 
} else { 
    id = bar.getFooId().intValue(); 
} 
get(bar.getFooClass(), id); 

這一個工程。顯然這與三元操作符有關。但爲什麼?有人能解釋這裏發生了什麼嗎?

+6

沒有足夠的信息。不要複述代碼,也不要總結錯誤消息。根據你給我們的情況,我可能會或可能無法弄清楚什麼是錯誤的,但我不會花太多時間在上面,因爲我可以告訴你沒有給我們任何完整的東西。 – arcy

+0

與你的問題沒有關係,但你爲什麼不讓'getFooId()'返回一個'Number'而不是額外的方法和類型轉換? – shmosel

+1

投票重新開放,因爲另一個問題沒有討論三元表達式或裝箱值。 – shmosel

回答

10

這是一個很好的問題,並進入了三元表達語義的細節。不,你的編譯器沒有壞掉,或者玩弄你的技巧。

在這種情況下,如果類型的三元表達式的第二和第三運算數的是longint,然後將所得的類型總是long。這是由於binary numeric promotion

按照JLS (Java Language Specification)

...,二進制數值提升施加到操作數類型,以及條件表達式的類型是所述第二和第三操作數的提升的類型。

的值由於規則#二進制數值1的促進得到裝箱:

如果任何操作數是參考的類型,將其進行解包轉換

這意味着什麼本質上,即當你有三元表達式時,表達式的結果類型必須是靜態確定的(在編譯時)。第二個和第三個操作數必須強制爲單一類型,即表達式的類型。如果兩個操作數都是數字類型,則啓用二進制數字提升以確定表達式的最終類型。

+0

顯式盒裝類型呢?它是否取消裝箱?爲什麼? – shmosel

+0

很好的答案。像@shmosel提到的那樣,它會更完整地告訴爲什麼編譯器在遇到帶有條件的三元運算符時?長:int'或'條件?長:整數',決定自動取消「長」形成'條件?長:int'。形式'條件? Long:Integer'在這裏也應該是有效的? –

+0

編輯回答上述問題。 –

相關問題