Java_泛型—generic

泛型,在我們日常的Java編程中是很常見的,例如List<String> list = new ArrayList<String>(); 這句代碼中,String就是泛型

泛型的本質:參數化類型,也就是說所操作的數據類型被指定爲一個參數。

這句話怎麼理解呢?說到參數,那就得說方法,我們經常定義方法的時候是不是要傳固定的參數類型,可以理解爲參數類型不固定了,在執行方法的時候才確定方法的參數類型。

看到這裏肯定不好理解,往下看吧!

泛型的由來,先看一段代碼:


說明:來來來,先看看代碼:line11-17 是引入泛型之前,line20-24 是引入泛型之後的

接下來解釋一下,看看這兩段代碼有什麼區別?

1:在沒引入泛型之前,List中,什麼類型都可以存進去(其實都以Object的類型存進去的),而加入泛型之後,就只能添加泛型指定的類型了。看line22,當你往List中添加int類型的數據的時候就會報錯。

2:在引入泛型之前,我們取出來的數據都是Object,那麼當我們要使用的時候就要強轉成我們當初存進去的類型,看line16;而引入泛型之後,我們就不用對取出來的數據進行強制轉換,可以直接使用了。看line24。

3:安全性問題:可以嘗試一下,把line20-24先註釋掉,點擊以下運行,就會出現ClssCastException(類型轉換異常),提示我們不能將Int類型強制轉換成String,再來看看這段代碼中報錯的那行,line22,其實報的就是同一種錯誤,只不過line22在編譯的時候報錯了,而line17是在運行的時候出錯了,這就很簡單了,其實就是將可能出現的錯誤在編譯的時候能夠及時的發現,在運行的時候就可以儘量的減少程序的錯誤;

總結:泛型的好處1:避免了強轉的麻煩;2:解決了安全性的問題(將運行時可能出現的異常轉移到了編譯的時候)。


泛型的使用:集合,這無疑是最常見的,當我們定義一個List的時候,一般都會指定這個集合要存儲的對象的類型-->泛型。


泛型的類型:

泛型可以定義在中,也可以定義在方法中,還可以定義在接口中。


泛型定義的位置

類和接口:定義在類名的後面,例如:class Animal<X> {}

方法:在修飾符後面,方法返回值的前面,例如:public <X> get(){}


下面來看看泛型定義在類中


看代碼line12:泛型類定義的開始。這裏定義了一個Printer類,同時定義了一個泛型X(X只是泛型的代表,可以使用任意的字母,例如:T,E,等都可以)

line13:聲明一個泛型的變量mX

line15:類的構造方法

line19:一個打印方法,方法裏面就是對泛型類型進行簡單的輸出,在控制檯上打印出來;

最後看一下line6-7:這兩行是對定義的泛型類的使用,定義類的時候泛型是放在類名後面的,所以使用的時候也一樣,放在類名的後面。然後看line6後半句,new Printer類的時候傳入一個String類型的數據,這個很好理解,構造方法中需要傳入的是一個泛型類型的數據,你在聲明的時候已經指定泛型是Sring,那麼你這裏也就相應的傳入String類型的數據,同理:如果你在泛型中指定的是Integer,那麼你這裏就相應的傳入int類型的數據;


看完了泛型的類,接下來我們看看泛型定義在方法中

看代碼:現在的代碼清爽很多了。line12-20是整個自定義的一個類,類中並不涉及到泛型,只是在print方法中定義了一個泛型X,同時,方法需要傳一個泛型類型的數據,最後是打印,就這麼簡單。再看看line6-7:line6是不是沒有泛型了,line7中也不見了泛型的蹤影,這去哪了呢?其實很簡單,在方法執行的時候會去檢測一下傳進去的類型的數據,然後再執行方法體。


來來來,我們對泛型進行一下小小的升級改造,還是看代碼:


代碼中。我們不僅把泛型定義在了類中。也定義在了方法(print2)中,然後再看看line8-9,可以看出,泛型方法是不受泛型類的限制的。有興趣的可以嘗試一下,將我這個小例子升級一下,在print2方法升級一下,寫一個print3,print3中既有泛型類中的泛型,又有泛型方法中的泛型,看看咋樣。嘿嘿。

既然泛型可以定義在方法中,那麼泛型是不是也可以定義在靜態方法中呢?

對,沒錯,泛型也可以定義在靜態方法中,看代碼:


代碼就不過多的解釋咯,一看就明白。但有一點要說明的是:泛型定義在方法的修飾符的後面,返回值類型的前面,這個位置是不變的,不論你前面有多少個修飾符,都是一樣的,位置很重要,不信你可以試試定義在其他地方試試看!


泛型類和泛型方法都講完了,該講講泛型定義在接口上了,接口也是類,人家也是一個java文件,對吧,爲什麼你不在介紹完類後介紹接口呢?你覺得一個接口中不定義方法的話,你覺得這個接口還有什麼用?對吧。不對不對,你可以將泛型定義在類中,不定義在方法中啊?我問你是不是傻,既然定義在類中了,你方法中沒使用這個泛型,你覺得有用麼?沒用的話,你定義泛型幹嘛?對吧。

下面還是看代碼:


看代碼line11-13:定義了一個名字爲Print的接口,接口中帶一個泛型的參數。然後line12定義一個print的抽象方法,方法中需要傳入一個泛型類型的參數;

接下來看line15-21:這是接口Print的實現類。這裏指定了泛型的類型是String,然後你可以使用ec的自動生成代碼的功能,讓他自動生成,然後你會發現,自動生成的代碼中,print方法中參數類型自動會定義成這個泛型,沒錯,就是這樣。你外面定義的是什麼,裏面定義的也就是什麼。

最後看一下ling6-7,line6中,定義了一個PrintImpl類對象,你會發現,我們定義這個類中是沒有泛型的,不用像前面那樣,要定義一個泛型進去,這很簡單嘛。你在實現類裏面已經指定泛型就是String,還需要再指定嘛?繼續看line7,ling7中,你把傳進去的數據刪掉,你就會發現,它會自動提示你需要傳一個String類型的數據,這也很好理解嘛。你line18中的方法中需要的是String,我這邊肯定也就是String啦。


看完這段代碼接下來看看升級版:


這個有設麼區別呢?區別肯定是有的,這個和上面那個相比,這個更加靈活,我們在接口的實現類中沒有指定相應的泛型類型,再看ling6,在使用的時候再去指定泛型的類型,這靈活度跟上面那個就有千差萬別了,在這裏,你可以再new一個對像,泛型的類型指定爲Integer類型,然後再print方法中相應的傳入int類型的數據。很靈活吧,再去看看前面那個,能做到傳int類型的數據麼?不是不可以,你需要再寫一個改接口的實現類而已,哈哈!


從上面的例子可以看出,泛型使用的範圍和方法參數使用的範圍很相似。當泛型定義在類(接口)中的時候,泛型在整個類(接口)中是有效的,當泛型定義在方法中,泛型在整個方法中是有效的。


泛型的類,方法,接口都看完了,接下來我們看看泛型的高級應用:

通配符:?

通配符在java中是很常用的,在泛型中,也有通配符的存在,接下來還是看代碼


還是Printer的例子,不同的是,我把print方法抽取出來了。然後添加一個get和set,來獲取和設置要打印的數據。

接着看line12-14,print方法,打印方法中需要傳入一個Printer,line13,輸出打印者要打印的數據。其中,line12中,<>裏面的不再是具體的類型(String,Integer,等等)也不是泛型,而是一個通配符?。可以理解爲,不知道里面是什麼類型,來什麼是什麼。如果比較難理解的話,可以看下面這段代碼:


先看line15和line19的這兩個方法的代碼。然後再看line6-9,現在清楚了吧。清楚就往下看,看line24,這個方式其實就是前面line15和19這兩個方法的合併,加入泛型之後合併成一個方法了,再看line11和12,是不是可以正常的調用這個方法,這就對了嘛,泛型不就體現出來了麼。然後接着看上面那段有佔位符?的代碼,有佔位符的方法和這段代碼中的line24有啥區別?看看就明白咯。


接下來看看泛型的上限和下限

上面那個例子,不是沒有對通配符?做限制麼。來什麼就是什麼,現在我們要對它進行限制,也就有了上限和下限,上限,很簡單嘛,就是規定了最大的那個,下限,就是規定最小的那個,暫且先這麼理解唄。

看代碼:


這個例子中,除了printer以外,還有3個類,分別是Animal,Cat,Dog三個類,他們三個的關係如右,Cat和Dog都是繼承子Animal的。

接下來看代碼line7-9,這三行代碼不多的解釋,然後看line10-12,這三行代碼調用print方法進行打印動物,可以看到,既可以打印Animal,也可以打印Cat和Dog,然後再來看看line20的print方法,print方法中,我們可以看到,對泛型T做了限制,規定了T的上限Animal,也就是說,只能夠接收Animal和Animal的子類,剛好Cat和Dog都是繼承自Animal,這不就對了麼,它只能接收Animal和其子類,信不信?不信你可以new一個Printer,然後裏面的泛型爲String或其他類型(反正不能是Animal的子類),然後調用print方法的時候傳入這個printer,看看會不會報錯,答案是肯定的。最後,看看line24的那個方法,這個方法和line20的在功能上是沒設麼區別的,只是寫法不一樣,一個用通配符表示而已。

這就是泛型的上限,那下限呢?

上限都搞清楚了,下限就很簡單了嘛,跟extends相對應的關鍵字是神碼?答案是:super

沒錯,上限就是只需要把extends改成super即可。

例子我就不再寫了,直接將 line24中的 extends 改成 super ,然後你可以看到,line 15 和line16就報錯了,這很容易解釋嘛,上限是規定可以使用自身及其子類,那麼下限就是規定了可以使用其自身和其父類嘛,Cat和Dog是Animal的子類,而不是Animal的父類,所以就報錯咯,就這麼簡單,別急別急,先別急着刪代碼嘛,我們再把line24中的Animal改成Cat,你會發現,現在只剩下line16報錯了。line15不報錯了,這下徹底明白了吧!


OK,泛型就寫到這裏!


如果你覺得這篇文章寫的好就點個讚唄,如果覺得寫的不好就指點一二唄。小弟我也是剛入門的。謝謝!



發佈了38 篇原創文章 · 獲贊 25 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章