一、簡單理解泛型
泛型是Java SE 1.5的新特性,泛型的本質是參數化類型,也就是說所操作的資料型態被指定為一個參數。通俗點將就是「類型的變數」。這種類型變數可以用在類別、介面和方法的建立中。
理解Java泛型最簡單的方法是把它看成一種便捷語法,能節省你某些Java類型轉換(casting)上的操作:
List<Apple> box = new ArrayList<Apple>();box.add(new Apple());Apple apple =box.get(0);
上面的程式碼自身已表達的很清楚:box是一個裝有Apple物件的List。 get方法傳回一個Apple物件實例,這個過程不需要進行類型轉換。沒有泛型,上面的程式碼需要寫成這樣:
Apple apple = (Apple)box.get(0);
二、泛型的尷尬
泛型的最大優點是提供了程式的類型安全同時可以向後相容,但也有尷尬的地方,就是每次定義時都要寫明泛型的類型,這樣顯示指定不僅感覺有些冗長,最主要是很多程式設計師不熟悉泛型,因此很多時候不能夠給出正確的類型參數,現在透過編譯器自動推斷泛型的參數類型,能夠減少這樣的情況,並提高程式碼可讀性。
三、java7的泛型類型推斷改進
在以前的版本中使用泛型類型,需要在聲明並賦值的時候,兩側都加上泛型類型。例如:
Map<String, String> myMap = new HashMap<String, String>();
你可能覺得:老子在宣告變數的時候已經指明了參數類型,為毛還要在初始化物件時再指定?幸好,在Java SE 7中,這種方式得以改進,現在你可以使用如下語句進行宣告並賦值:
Map<String, String> myMap = new HashMap<>(); //注意后面的"<>"
在這條語句中,編譯器會根據變數宣告時的泛型類型自動推斷出實例化HashMap時的泛型類型。再次提醒一定要注意new HashMap後面的“<>”,只有加上這個“<>”才表示是自動類型推斷,否則就是非泛型類型的HashMap,並且在使用編譯器編譯原始碼時會給出一個警告提示。
但是:Java SE 7在創建泛型實例時的類型推斷是有限制的:只有構造器的參數化類型在上下文中被顯著的聲明了,才可以使用類型推斷,否則不行。例如:下面的例子在java 7無法正確編譯(但現在在java8裡面可以編譯,因為根據方法參數來自動推斷泛型的類型):
List<String> list = new ArrayList<>(); list.add("A");// 由于addAll期望获得Collection<? extends String>类型的参数,因此下面的语句无法通过 list.addAll(new ArrayList<>());
四、Java8的泛型類型推斷改進
java8裡面泛型的目標類型推斷主要2個:
1.支持透過方法上下文推斷泛型目標類型
2.支持在方法調用鏈路當中,泛型類型推斷傳遞到最後一個方法
讓我們看看官網的例子:
class List<E> { static <Z> List<Z> nil() { ... }; static <Z> List<Z> cons(Z head, List<Z> tail) { ... }; E head() { ... } }
根據JEP101的特性,我們在調用上面方法的時候可以這樣寫
//通过方法赋值的目标参数来自动推断泛型的类型 List<String> l = List.nil(); //而不是显示的指定类型 //List<String> l = List.<String>nil(); //通过前面方法参数类型推断泛型的类型 List.cons(42, List.nil()); //而不是显示的指定类型 //List.cons(42, List.<Integer>nil());
五、總結
以上是JEP101的特性內容了,Java作為靜態語言的代表者,可以說類型系統相當豐富。導致類型間互相轉換的問題困擾著每個java程式設計師,透過編譯器自動推斷類型的東西可以稍微緩解一下類型轉換太複雜的問題。 雖然說是小進步,但對於我們天天寫程式碼的程式設計師,肯定能帶來巨大的作用,至少心情更愉悅了~~說不定在java 9裡面,我們會得到一個通用的類型var,像js或者scala的一些動態語言那樣^_^
更多Java8中對泛型目標類型推斷方法的改進相關文章請關注PHP中文網!