2011-12-28 61 views
8

我想這可能與Why does a generic cast of a List<? extends Set..> to List<Set..> succeed on Sun JDK 6 but fail to compile on Oracle JDK 7?JDK 7中的類型推斷在JDK 6中比JDK 6更具限制性?

如果我們把下面的類,他們編細下JDK 6:

public final class Foo<V> { 

    private final V value; 

    private Foo(final V value) { 

     this.value = value; 
    } 

    public static <T, R extends T> Foo<T> of(final R value) { 

     return new Foo<T>(value); 
    } 
} 

final class Tester { 

    @Test(groups="unit") 

    public static void test() { 

     bar(Foo.of(BigDecimal.ZERO)); // This line fails in JDK 7 but not JDK 6 
    } 

    private static void bar(final Foo<? extends Number> target) { 

     assert target != null; 
    } 
} 

然而,JDK 7下,我收到以下錯誤:

[ERROR] \work\fsb-core\src\test\java\com\fsb\core\Foo.java:[42,8] error: 
       method bar in class Tester cannot be applied to given types; 

我認爲JDK 7中類型推斷的限制較少(例如,添加構造函數推理)。但是,此處編譯器拒絕在JDK 6下有效的類型。

這是一個錯誤?或者推理規則對方法更嚴格?

+0

Java 8(1.8.0_25)這個編譯就好了。 – Lii 2015-04-04 16:21:40

回答

3

嚴格按照規範,T無法推斷(根據15.12.2.7),所以它應該被視爲Object

這可以視爲規範的失敗。這是如何推斷R:首先有約束R :> BigDecimal,其中:>意味着是一個超類型。推理規則然後選擇R=BigDecimal,因爲它是滿足約束的最具體的類型。

現在,由於T:>R,T:>BigDecimal,人們會認爲這也應該產生T=BigDecimal

不幸的是,推理規則不考慮T:>RT沒有任何限制。 T不是通過相同的原理推斷的。

儘管它很糟糕,spec是spec。你的代碼不應該編譯。 Javac6在那裏是錯誤的。

在Java 8中,推理規則有很大的改進,使得lambda表達式更易於使用。希望你的代碼應該在Java 8中編譯。

+0

謝謝你的解釋。對於JDK 7中的類型推斷是正確的,我感到寬慰(有點沮喪,它只在JDK 6中偶然地工作)。這似乎與http://www.oracle.com/technetwork/java/javase/compatibility-417013.html有關。 (最初引用http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6638712)。 – Saish 2011-12-28 22:17:41