實現這種通用算術思想存在一個基本問題。這個問題並不在於如何在數學上說這應該起作用,而在於它應該如何編譯爲Java編譯器的字節碼。
在你的榜樣,你有這樣的:
class MathOperationV1<T extends Number> {
public T add(T a, T b) {
return a + b; // error: Operator '+' cannot be applied to 'T', 'T'
}
}
留裝箱和拆箱不談,問題是,編譯器不知道應該如何編譯+
運營商。編譯器應使用+
的多個重載版本中的哪一個?對於不同的基元類型,JVM具有不同的算術運算符(即操作碼);因此整數的和運算符與雙精度運算符完全不同(例如,請參閱iadd與dadd)。如果仔細考慮它,那完全有意義,因爲畢竟整數運算和浮點運算是完全不同。不同的類型也有不同的尺寸等(參見例如ladd)。另外請考慮BigInteger
和BigDecimal
,它們也擴展爲Number
,但那些不支持自動裝箱,因此沒有操作碼直接處理它們。可能有其他幾十個其他類似於其他庫中的實現的其他Number
實現。編譯器如何知道如何處理它們?
因此,當編譯器推斷T
是Number
時,這不足以確定哪些操作碼對操作有效(即裝箱,拆箱和算術)。
後來你建議更改代碼位:
class MathOperationV1<T extends Integer> {
public T add(T a, T b) {
return a + b;
}
}
而且現在+
運營商可以用一個整數總和碼來實現,但總和的結果將是一個Integer
,而不是一個T
,但仍然會使此代碼無效,因爲從編譯器的角度來看,T
可能是Integer
以外的其他內容。
我相信沒有辦法讓代碼具有足夠的通用性,以至於您可以忘記這些底層實現細節。
- 編輯 -
爲了回答您的評論部分的問題考慮基於以上MathOperationV1<T extends Integer>
最後一個定義以下情形。
你是正確的,當你說,編譯器會做類型擦除的類定義,並且如果考慮到這種類型擦除,就好像使用它似乎是
class MathOperationV1 {
public Integer add(Integer a, Integer b) {
return a + b;
}
}
它會被編譯子類Integer
應該在這裏工作,但這不是真的,因爲它會使類型系統不健全。讓我試着證明這一點。
編譯器不僅可以擔心的聲明網站,它也有考慮在多個調用點會發生什麼,可能使用不同類型的論據T
。
例如,想象一下(爲了我的論點),有一個Integer
的子類,我們將其稱爲SmallInt
。假設我們上面的代碼編譯好了(這實際上是你的問題:爲什麼它不能編譯?)。
如果我們做了以下事情,會發生什麼?
MathOperationV1<SmallInt> op = new MathOperationV1<>();
SmallInt res = op.add(SmallInt.of(1), SmallInt.of(2));
正如你可以看到op.add()
方法的結果預計將是一個SmallInt
,而不是一個Integer
。然而,我們上面的a + b
的結果,從我們已刪除的類定義中,總是會返回Integer
而不是SmallInt
(因爲+使用JVM整數算術操作碼),因此這個結果是不合適的,對嗎?
您現在可能會想知道,但如果MathOperationV1
的類型刪除總是返回Integer
,那麼在呼叫站點的世界中它可能會有什麼其他的東西(如SmallInt
)呢?
好,編譯器在這裏增加了一些額外的施法者add
結果強制轉換爲SmallInt
,但只是因爲它已經保證了操作無法返回任何東西比預期的類型等(這就是爲什麼你看到編譯器錯誤)。
換句話說,您的通話網站看起來像這樣擦除之後:
MathOperationV1 op = new MathOperationV1<>(); //with Integer type erasure
SmallInt res = (SmallInt) op.add(SmallInt.of(1), SmallInt.of(2));
但是,如果你能保證add
回報總是SmallInt
(我們不能因操作問題描述了只會工作在我原來的答案)。
所以,你可以看到,你的類型擦除只是確保在於,根據分型的規則,你可以返回任何延伸的Integer
,但一旦您的通話網站聲明瞭T
一種說法,你應該在原始代碼中出現T
以保持類型系統聲音時始終假設爲相同類型。
您實際上可以通過使用Java反編譯器(您的JDK bin目錄中名爲javap的工具)來證明這些觀點。我可以提供更好的例子,如果你認爲你需要它們,但你會自己嘗試一下,看看底下發生了什麼:-)
請將相關的語言標籤添加到您的問題。 –
這是Java,不是嗎? – lilezek
我剛更新了標題,提醒! –