2014-09-30 53 views
3

這似乎是一個非常愚蠢的問題,但我不明白爲什麼使用Optional<T>編譯:Java:如何使用Optional.empty()編譯?

import java.util.Optional; 

public class Driver { 
    static void foo(Optional<String> x) { } 

    public static void main() { 
     foo(Optional.empty()); 
    } 
} 

Optional::empty被定義爲返回我的Optional<T>。在Driver::main的內部,表達式Optional.empty()好像會返回Optional<Object>,因爲我沒有參數化使用Optional,所以我期望它會回退到Object作爲類型參數。然後,我將Optional<Object>傳遞給一個函數,期望Optional<String>,這是一個不應該被允許的參數向下。我期望看到類似於:

incompatible types: Optional<Object> cannot be converted to Optional<String> 

但是,代碼編譯完美。顯然,我在這裏的思維過程是不正確的......但是在哪裏?


讓我在這裏澄清我在尋找答案...我知道什麼類型的推論。我不明白怎麼這裏發生什麼在語言改變從Java 7到Java 8。例如,這段代碼在編譯的Java 8完美的罰款,但沒有在Java中7:

final class Opt<T> { 
    private final T value; 

    Opt(T x) { 
     value = x; 
    } 

    public static <T> Opt<T> empty() { 
     return new Opt<T>(null); 
    } 
} 

public class Driver { 
    static void bar(Opt<String> x) { } 

    public static void main() { 
     bar(Opt.empty()); 
    } 
} 

這是如何工作在Java 8中,當你不得不處理像重載這樣的事情?有沒有關於這種事情的Java語言規範的特定部分?

+3

類型推斷是一件很酷的事情 – 2014-09-30 20:33:21

+0

這並不能有效回答這個問題。 – 2014-09-30 20:38:02

回答

9

這是由於的方式的方式空()方法是在可選定義:

public static<T> Optional<T> empty() { 
    @SuppressWarnings("unchecked") 
    Optional<T> t = (Optional<T>) EMPTY; 
    return t; 
} 

注意上述方法類型參數:

public static<T> Optional<T> empty() { 
      ^^^ method type parameter 

這意味着空時()被調用,它會綁定T到它的調用者的上下文,在你的情況下字符串。欲瞭解更多信息,請參閱本頁面的Java教程的目標類型的部分:

http://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html

+0

+1類型參數。儘管對推理部分不太確定。我的意思是,一個類型參數聲明是非常明確的。 – rompetroll 2014-09-30 20:51:03

-1

Java 8添加了類型接口,這意味着它將基於它如何使用來計算表達式的類型。

甲blatent例子是

Object o =() -> System.out.println("Hello World"); 

不編譯,因爲它不知道然而表達式的類型,

Runnable r =() -> System.out.println("Hello World"); 

Object o = (Runnable)() -> System.out.println("Hello World"); 

編譯細。即表達式的類型因使用方式而改變。

0

它因爲編譯器類型推斷。

當編譯器閱讀:

static void foo(Optional<String> x) { } 

public static void main() { 
    foo(Optional.empty()); 
} 
  • 它知道Optional.<T>empty()採取T作爲參數。
  • 它知道foo期待一個Optional<String>
  • 據推斷TString

它是在引入泛型時引入的,也可能是Java 8的javac改進了它的機制。請注意,這取決於編譯器:ECJ(Eclipse JDT編譯器)不理解Javac理解的同一個Java源代碼(但它們會編譯「相同」的字節代碼)。

8

因爲你的問題的那部分還沒有得到解決,我會嘗試總結一下有Java的7和Java 8

的Java 7之間改變已有類型推斷,例如你可以寫

List<String> list=Collections.emptyList(); 

List<String> getList() { 
    return Collections.emptyList(); 
} 

但這種類型推斷是相當有限的,例如什麼沒有工作(除了其他)爲:

List<String> list=Collections.unmodifiableList(Collections.emptyList()); 

List<String> getList() { 
    return condition? new ArrayList<>(): Collections.emptyList(); 
} 

這兩個例子現在的Java 8下工作時,此新功能稱爲目標類型推斷因爲它採用了目標的鍵入查找適當的類型參數。除了使嵌套的方法調用和條件的工作,如在上面的例子中,還修復了以下例子:

List<Number> numbers=Arrays.asList(1, 2, 3, 4); 

至於說,Java 7中有類型推斷太多,但在這個例子中,將推斷List<Integer>爲來自傳遞給asList的參數的表達式的結果類型,並因此生成一個錯誤。

相比之下,Java的8具有目標類型推斷並且將使用賦值的目標類型推斷List<Number>作爲表達的類型,並找出整個語句是有效的,你可以使用Integer對象,其中Number是期待。

請注意,Optional.empty()Collections.emptyList()使用相同種類的Generic構造。我在我的例子中使用了後者,因爲它已經存在於Java 7中。

相關問題