這是不是一個錯誤的javac,根據當前規範。我在這裏寫了一個答案,是類似於issue的SO。這裏的問題差不多是一樣的。
在賦值或調用上下文中,引用條件表達式是多表達式。這意味着表達式的類型不是將採集轉換應用於lub(T1,T2)的結果,有關T1和T2的詳細定義,請參閱JSL-15.25.3。相反,我們有,還從規範的這一部分是:
Where a poly reference conditional expression appears in a context of a particular kind with target type T, its second and third operand expressions similarly appear in a context of the same kind with target type T.
The type of a poly reference conditional expression is the same as its target type.
因此,這意味着目標類型被向下推到基準條件表達式的兩個操作數,並且兩個操作數都對該目標類型歸屬。因此,編譯器最終收集來自兩個操作數的約束,導致無法解析的約束集,從而導致錯誤。
好的,但爲什麼我們在這裏得到T的平等界限?
讓我們來詳細看看,從呼叫:
foo(true ? String.class : StringBuilder.class)
其中foo是:
static <T> T foo(Class<T> clazz) throws Exception {
return clazz.newInstance();
}
我們有,我們正在調用方法foo()
與表達true ? String.class : StringBuilder.class
。該引用條件表達式應該在類型爲Class<T>
的鬆散調用上下文中兼容。這表現爲,見JLS-18.1.2:
true ? String.class : StringBuilder.class → Class<T>
由於從JLS-18.2.1下面我們有:
A constraint formula of the form ‹Expression → T› is reduced as follows:
...
- If the expression is a conditional expression of the form e1 ? e2 : e3, the constraint reduces to two constraint formulas, ‹e2 → T› and ‹e3 → T›.
這意味着,我們得到以下約束公式:
String.class → Class<T>
StringBuilder.class → Class<T>
或:
Class<String> → Class<T>
Class<StringBuilder> → Class<T>
後來從JLS-18.2.2我們有:
A constraint formula of the form ‹S → T› is reduced as follows:
...
- Otherwise, the constraint reduces to ‹S <: T›.
我只包括相關零部件。所以怎麼回事,我們現在有:
Class<String> <: Class<T>
Class<StringBuilder> <: Class<T>
從JLS-18.2.3,我們有:
A constraint formula of the form ‹S <: T› is reduced as follows:
...
- Otherwise, the constraint is reduced according to the form of T:
- If T is a parameterized class or interface type, or an inner class type of a parameterized class or interface type (directly or indirectly), let A1, ..., An be the type arguments of T. Among the supertypes of S, a corresponding class or interface type is identified, with type arguments B1, ..., Bn. If no such type exists, the constraint reduces to false. Otherwise, the constraint reduces to the following new constraints: for all i (1 ≤ i ≤ n), ‹Bi <= Ai›.
那麼作爲Class<T>
,Class<String>
和Class<StringBuilder>
是參數化的類,這意味着我們現在的限制減少到:
String <= T
StringBuilder <= T
也從JLS-18.2.3,我們有:
A constraint formula of the form ‹S <= T›, where S and T are type arguments (§4.5.1), is reduced as follows:
...
- If T is a type:
- If S is a type, the constraint reduces to ‹S = T›.
因此,我們最終與這些約束T:
String = T
StringBuilder = T
最後,在JLS-18.2.4我們有:
A constraint formula of the form ‹S = T›, where S and T are types, is reduced as follows:
...
- Otherwise, if T is an inference variable, α, the constraint reduces to the bound S = α.
並且對於類型變量T沒有溶液與界限T = String
和T = StringBuilder
。編譯器沒有類型可以替代T來滿足這兩個限制。爲此,編譯器顯示錯誤消息。
因此,根據目前的規範,javac是可以的,但是規範正確嗎?那麼應該調查7和8之間的兼容性問題。由於這個原因,我已經提交JDK-8044053,所以我們可以跟蹤這個問題。
這是因爲它改進了類型推斷。 – berry120
@ berry120你認爲這是一個改進? :) –
在這個例子中,我看到了你試圖更清楚地表達的觀點 - 我同意,在我看來,三元操作符並不是以它應該做的方式來推斷類型。 – berry120