2015-09-06 76 views
1

我在的IntelliJ寫這個類。冗餘類型參數

public class Main { 

    public static void main(String[] args) { 
     Main.<Number>foo(0); 
     Main.<Integer>foo(0); 
    } 

    static <T> void foo(T t) {} 
} 

Main.<Number>foo(0);不會產生任何消息,但對下一行我得到的消息

明確的類型參數可以推斷。 該檢驗報告所有的呼叫,參數化,其中 明確的參數類型可以省略的方法,因爲他們將 由編譯器清楚地確定。

這沒有任何意義,我在所有。我的理解是所有類型的參數都被擦除了,所以類型參數是否含糊不清。至於我可以告訴用於調用返回類型爲void泛型方法時提供過一個類型參數的唯一原因是說服一個類型T所需的範圍內存在的編譯器。除此之外,它應該沒有什麼區別你實際提供的類型參數。所以如果在第二種情況下類型參數是多餘的,那麼在第一種情況下它應該是多餘的。任何人都可以解釋這些消息何時出現的規則是如何工作的,以及爲什麼在這種情況下規則甚至應該取決於提供的類型參數?

回答

2

我從來沒有看到消息,但它看起來像一個警告。

首先觀察的是,這個來自的IntelliJ編譯到來。當我使用Java 8 javac進行編譯時,沒有這種警告消息。

另外要注意的是,在這種情況下沒有區別什麼類型的編譯器推斷爲T這裏。我認爲這就是編譯器告訴你的。

可能問題如果方法返回T並且您將結果分配給變量(例如)。例如:

Integer i = Main.<Integer>foo(0); // OK 
    i = Main.foo(0);     // OK 
    i = Main.<Long>foo(0L);   // Error 
    i = Main.foo(0L);     // Different error message. 

在第三情況下,(javac)編譯器說Long不能被分配給Integer

在過去的情況下,(javac)編譯器將指示foo將返回Long和它說,推斷的類型不能進行分配。


我不明白爲什麼你應該永遠必須提供一個類型參數。

考慮這樣foo調用的結果作爲一個重載方法的參數的情況下,你需要一個特定的結果類型來獲取Java調用正確的過載。

還值得一提的是,Java的8位的類型推斷是比早期版本更復雜。 Java版本較舊的情況下,推理需要一些明確的類型參數幫助。

+0

我不明白在Eclipse的警告要麼。 – Andreas

2

這只是一個警告,說明指定類型是不必要的。

由於T是一個對象,並且不能是原語,所以0參數將被裝箱到Integer。這意味着編譯器會推斷T表示Integer,因此指定它是多餘的。

的參數進行裝箱到Integer無論您指定的參數的類型。例如。 Test.<Long>foo(0)將不會編譯,因爲IntegerLong不兼容。

1

從文檔上通用的方法https://docs.oracle.com/javase/tutorial/extra/generics/methods.html

,我們沒有一個實際的類型參數傳遞給泛型方法的通知。編譯器根據實際參數的類型推斷我們的類型參數。它通常會推斷最具體的類型參數,使得調用類型正確。

由於Integer是您的案例中最具體的類型,因此指定它是多餘的。由於Number是一個更一般的類型,它不是多餘的。

而且,你是正確的,有因類型擦除兩個調用運行時沒有區別。

這裏
0

其他答案已經解釋了爲什麼可以省略類型參數。

至於爲什麼這是擺在首位的警告,這是因爲你的代碼是多餘的。 DRY原理說你永遠不應該寫冗餘代碼,所以你的IDE編譯器會有幫助地警告你寫了冗餘的,不必要的代碼。

即使在情況下,它不會有所作爲編譯結果,或在運行時的行爲(有些人會說,特別是),但仍值得去除冗餘代碼。所以我認爲這是一個很好的警告,最好遵循它的建議。