一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語言 - JAVA教程 - 詳談Java8新特性泛型的類型推導

詳談Java8新特性泛型的類型推導

2020-06-09 12:09daisy JAVA教程

這篇文章我們來看一篇關(guān)于Java8新特性之泛型的類型推導,希望這篇文章能夠讓各位深入到了解到關(guān)于Java8新特性之泛型的類型用法,有需要的朋友們下面來一起看看吧。

1. 泛型究竟是什么?

  在討論類型推導(type inference)之前,必須回顧一下什么是泛型(Generic).泛型是Java SE 1.5的新特性,泛型的本質(zhì)是參數(shù)化類型,也就是說所操作的數(shù)據(jù)類型被指定為一個參數(shù)。通俗點將就是“類型的變量”。這種類型變量可以用在類、接口和方法的創(chuàng)建中。理解Java泛型最簡單的方法是把它看成一種便捷語法,能節(jié)省你某些Java類型轉(zhuǎn)換(casting)上的操作:

?
1
2
List<Apple> box = new ArrayList<Apple>();box.add(new Apple());
Apple apple =box.get(0);

上面的代碼自身已表達的很清楚:box是一個裝有Apple對象的Listget方法返回一個Apple對象實例,這個過程不需要進行類型轉(zhuǎn)換。沒有泛型,上面的代碼需要寫成這樣:

?
1
Apple apple = (Apple)box.get(0);

當然,泛型絕不像我在這里描述的這么簡單,但這不是我們今天的主角,對于泛型還不是很明白的同學需要補課了~當然,最好的參考資料還是官方文檔。

2. 泛型帶來的問題(Java 7之前)

泛型的最大優(yōu)點是提供了程序的類型安全同時可以向后兼容,但也有讓開發(fā)者不爽的地方,就是每次定義時都要寫明泛型的類型,這樣顯示指定不僅感覺有些冗長,最主要是很多程序員不熟悉泛型,因此很多時候不能夠給出正確的類型參數(shù),現(xiàn)在通過編譯器自動推斷泛型的參數(shù)類型,能夠減少這樣的情況,并提高代碼可讀性。

3. Java 7中對于泛型的類型推導方面的改進

在Java 7以前的版本中使用泛型類型,需要在聲明并賦值的時候,兩側(cè)都加上泛型類型。比方說這樣:

?
1
Map<String,Integer> map = new HashMap<String,Integer>();

很多人當初肯定和我一樣,對此感到很不解:我在變量聲明中不是已經(jīng)聲明了參數(shù)類型了嗎?為什么在對象初始化的時候還要顯示的寫出來?這也是泛型在一開始出現(xiàn)的時候受到很多人吐槽的地方。不過,讓人欣慰的是,java在進步的同時,那些設(shè)計者們也在不斷的改進java的編譯器,讓它變的更加智能與人性化。這里,就是我們今天的主角:類型推倒...額...不是推倒,是類型推導,即type inference,這哥們兒的出現(xiàn),再寫上面這樣的代碼的時候,可以很開心地省略掉對象實例化時的參數(shù)類型,也就變成了這個樣子:

?
1
Map<String,Integer> map = new HashMap<>();

在這條語句中,編譯器會根據(jù)變量聲明時的泛型類型自動推斷出實例化HashMap時的泛型類型。再次提醒一定要注意new HashMap后面的“<>”,只有加上這個“<>”才表示是自動類型推斷,否則就是非泛型類型的HashMap,并且在使用編譯器編譯源代碼時會給出一個警告提示(unchecked conversion warning)。這一對尖括號"<>"官方文檔中叫做"diamond"。

但是,這時候的類型推導做的并不完全(甚至算是一個半成品),因為在Java SE 7中創(chuàng)建泛型實例時的類型推斷是有限制的:只有構(gòu)造器的參數(shù)化類型在上下文中被顯著的聲明了,才可以使用類型推斷,否則不行。例如:下面的例子在java 7無法正確編譯(但現(xiàn)在在java8里面可以編譯,因為根據(jù)方法參數(shù)來自動推斷泛型的類型):

?
1
2
3
List<String> list = new ArrayList<>();
list.add("A");// 由于addAll期望獲得Collection<? extends String>類型的參數(shù),因此下面的語句無法通過
list.addAll(new ArrayList<>());

4. 在Java8中的再進化

在最新的java官方文檔之中,我們可以看到對于類型推導的定義:

Type inference is a Java compiler's ability to look at each method invocation and corresponding declaration to determine the type argument (or arguments) that make the invocation applicable. The inference algorithm determines the types of the arguments and, if available, the type that the result is being assigned, or returned. Finally, the inference algorithm tries to find the most specific type that works with all of the arguments.

簡言之,類型推導也就是指編譯器能夠根據(jù)你調(diào)用的方法和相應(yīng)的聲明來確定需要的參數(shù)類型的能力。并且官方文檔中還給出了一個例子加以詮釋:

?
1
2
static <T> T pick(T a1, T a2) { return a2; }
Serializable s = pick("d", new ArrayList<String>());

在這里,編譯器能夠推導出傳入pick方法中的第二個參數(shù)的類型是Serializable的。

在之前的java版本當中,上面的例子要能夠通過編譯的話需要這要寫:

?
1
Serializable s = this.<Serializable>pick("d", new ArrayList<String>());

這樣寫的詳細原因可以在Bruce Eckel的java編程思想(第四版)的泛型一章看得到,當然這本書是基于java6的,這個版本還沒有類型推導這個概念。看到這里,很多人已經(jīng)明顯能看得出來最新版本中類型推導的強力之處了。已經(jīng)不僅僅局限于泛型類的聲明與實例化過程了,而是延伸到了具有泛型參數(shù)的方法當中了。

4.1 類型推導和泛型方法(Type Inference and Generic Methods)

關(guān)于新版本中的類型推導和泛型方法,文檔中還給了一個稍微復雜一點的例子,我在這里貼出來,原理和上面的Serializable例子都是一樣就不再贅述,想鞏固的可以再看一下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class BoxDemo {
 
 public static <U> void addBox(U u,
 java.util.List<Box<U>> boxes) {
 Box<U> box = new Box<>();
 box.set(u);
 boxes.add(box);
 }
 
 public static <U> void outputBoxes(java.util.List<Box<U>> boxes) {
 int counter = 0;
 for (Box<U> box: boxes) {
 U boxContents = box.get();
 System.out.println("Box #" + counter + " contains [" +
  boxContents.toString() + "]");
 counter++;
 }
 }
 
 public static void main(String[] args) {
 java.util.ArrayList<Box<Integer>> listOfIntegerBoxes =
 new java.util.ArrayList<>();
 BoxDemo.<Integer>addBox(Integer.valueOf(10), listOfIntegerBoxes);
 BoxDemo.addBox(Integer.valueOf(20), listOfIntegerBoxes);
 BoxDemo.addBox(Integer.valueOf(30), listOfIntegerBoxes);
 BoxDemo.outputBoxes(listOfIntegerBoxes);
 }
}

上面這段代碼輸出為:

?
1
2
3
Box #0 contains [10]
Box #1 contains [20]
Box #2 contains [30]

提一下,泛型方法addBox重點就在于在新java版本中你不需要再在方法調(diào)用中進行顯示的類型說明,像這樣:

?
1
BoxDemo.<Integer>addBox(Integer.valueOf(10), listOfIntegerBoxes);

編譯器能夠從傳入addBox中的參數(shù)自動推斷出參數(shù)類型是Integer.

4.2 類型推導與泛型類和非泛型類的泛型構(gòu)造器(Type Inference and Generic Constructors of Generic and Non-Generic Classes)

額...這個也許英語的更好斷句一點:Type Inference and Generic Constructors of Generic and Non-Generic Classes

其實,泛型構(gòu)造器并不是泛型類的專利品,非泛型類也完全可以有自己的泛型構(gòu)造器,看一下這個例子:

?
1
2
3
4
5
class MyClass<X> {
 <T> MyClass(T t) {
 // ...
 }
}

假如對 MyClass類做出下面這樣的實例化:

?
1
new MyClass<Integer>("")

OK,這里我們顯示地指出了MyClass的泛參類型X是Integer,而對于構(gòu)造器,編譯器根據(jù)傳入的String對象("")推導出形式參數(shù)T是String,這個在java7版本之中已經(jīng)實現(xiàn)了,在Java8中有了什么改進呢?在Java8之后,對于這種具有泛型構(gòu)造器的泛型類的實例化我們可以這么寫:

?
1
MyClass<Integer> myObject = new MyClass<>("");

對,還是這一對尖括號(<>),江湖人稱diamond,這樣我們的編譯器就能夠自動推導出形式參數(shù)X是Integer,T是String了。這個其實和我們一開始Map<String,String>的例子很像,只是多了個構(gòu)造器的泛型化。

需要注意的是:類型推導只能根據(jù)調(diào)用的參數(shù)類型、目標類型(這個馬上會講到)和返回類型(如果有返回的話)進行推導,而不能根據(jù)程序后面的一些需求來進行推導。

4.3 目標類型(Target Type)

前文已經(jīng)提到過,編譯器能夠根據(jù)目標類型進行類型推導。一個表達式的目標類型指的是一種編譯器根據(jù)表達式出現(xiàn)的位置而需要的正確的數(shù)據(jù)類型。比如這個例子:

?
1
2
static <T> List<T> emptyList();
List<String> listOne = Collections.emptyList();

在這里,List<String>就是目標類型,因為這里需要的是List<String> ,而Collections.emptyList()返回的是List<T> ,所以這里編譯器就推斷T一定是String。這個在Java 7 和 8 中都OK。但是在java 7 中,在下面這種情況中就不能正常編譯了:

?
1
2
3
4
5
void processStringList(List<String> stringList) {
 // process stringList
}
 
processStringList(Collections.emptyList());

這個時候,java7就會給出這種錯誤提示:

?
1
//List<Object> cannot be converted to List<String>

原因:Collections.emptyList()  返回的是List<T> ,這里的T需要一個具體類型,但是因為不能從方法聲明中推斷出所需的是String,所以編譯器就給T了一個Object的值,很明顯,List<Object>不能轉(zhuǎn)型到List<String>.所以在java7版本中你需要這樣調(diào)用這個方法:

?
1
processStringList(Collections.<String>emptyList());

但是,在java8中,由于目標類型概念的引入,這里,很明顯編譯器需要的是List<String> (也就是這里的Target Type),所以編譯器推斷返回的List<T>中的T一定是String,所以processStringList(Collections.emptyList());這種描述是OK的。

目標類型的使用在Lambda表達式中優(yōu)勢最為明顯。

總結(jié)

好了,以上就是關(guān)于java中類型推導的一些個人見解,總結(jié)來說,越來越完善的類型推導就是完成了一些本來就感覺很理所當然的類型轉(zhuǎn)換工作,只是這些工作滿滿地全交給了編譯器去自動推導而不是讓開發(fā)者顯示地去指定。希望這篇文章的內(nèi)容對大家學習Java能有所幫助,如果有疑問可以留言交流。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 男女18一级大黄毛片免 | 91国产在线播放 | 精品日韩欧美一区二区三区 | 俄罗斯极品h在线 | avtt天堂在线 | 国产精品成人在线播放 | 女同xx美女放| 亚洲国产精品无圣光一区二区 | 亚洲欧美日韩成人一区在线 | 黑人性xxxⅹxxbbbbb | 高肉h护士办公室play | 男人的j放进女人的p全黄 | 四虎精品成人免费影视 | 国产精品高清视亚洲一区二区 | 女被男啪到哭 | 美女扒开胸罩露出奶了无遮挡免费 | 亚洲国产精久久久久久久 | 男人的天堂在线观看视频不卡 | 99视频在线观看视频一区 | 羞羞色男人的天堂伊人久久 | 亚洲成人免费 | 欧美又大又粗又长又硬 | 91亚洲一区二区在线观看不卡 | 男男gaygays国内 | 国产一区在线看 | 免费看日本 | 色花堂中文字幕98堂网址 | 奇米影视小说 | 免费看欧美一级特黄a大片一 | 好紧水好多 | hd最新国产人妖ts视频 | 日韩性事 | japanesexxxx在线播放 | 国产理论片在线观看 | 精品日韩欧美一区二区三区 | 国产精品福利在线观看秒播 | 国产欧美日韩视频在线观看一区二区 | 国产午夜永久福利视频在线观看 | 99在线播放 | 国内在线观看 | 欧美一级乱妇老太婆特黄 |