日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java基础知识(七)-- 泛型(Generics )

發布時間:2024/3/13 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java基础知识(七)-- 泛型(Generics ) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

介紹

用法:???

List list = new ArrayList();// 1 list .add(new Integer(12));// 2 Integer x = (Integer) list .iterator().next();// 3// 第3 行的類型轉換有些煩人,為了保證對Integer 類型變量賦值的類型安全,必須進行類型轉換。 //當然,因為程序員可能不清楚他們的類型,導致這個類型轉換有可能產生一個運行時錯誤。 //而如何把一個list(集合) 中的內容限制為一個特定的數據類型呢? //這就是generics背后的核心思想。這是上面程序片斷的一個泛型版本:List<Integer> list = new ArrayList<Integer>(); // 1 list.add(new Integer(12)); // 2 Integer x = list.iterator().next(); // 3//注意第1行變量list的類型聲明。 //它指定這不是一個任意的List,而是一個Integer 的List。 //我們說List是一個帶一個類型參數的泛型接口,我們在創建這個List 對象的時候指定了一個Integer類型參數是。 //另一個需要注意的是第3行沒了類型轉換。

??? 現在,我們用第1行的類型參數取代了第3 行的類型轉換。然而,這里還有個很大的不同。編譯器現在能夠在編譯時檢查程序的正確性。當我們說list 被聲明為ist<Integer>類型,這告訴我們無論何時何地使用list 變量,編譯器保證其中的元素的正確的類型。實際結果是,這可以增加可讀性和穩定性,尤其在大型的程序中。

泛型的設計背景

Java中的泛型是什么 ?

????????所謂泛型,就是允許在定義類、接口時通過一個標識表示類中某個屬性的類型或者是某個方法的返回值及參數類型。這個類型參數將在使用時(例如,繼承或實現這個接口,用這個類型聲明變量、創建對象時)確定(即傳入實際的類型參數,也稱為類型實參)。

????????集合容器類在設計階段/聲明階段不能確定這個容器到底實際存的是什么類型的對象,所以JDK1.5之前只能把元素類型設計為Object在集合中存儲對象并在使用前進行類型轉換是很不方便

????????JDK1.5之后使用泛型來解決。這個時候除了元素的類型不確定,其他的部分是確定的,例如關于這個元素如何保存,如何管理等是確定的,因此此時把元素的類型設計成一個參數,這個類型參數叫做泛型。Collection<E>List<E>ArrayList<E>這個<E>就是類型參數,即泛型。允許我們在創建集合時再指定集合元素的類型,正如:List<String>,這表明該List只能保存字符串類型的對象。

????????JDK1.5改寫了集合框架中的全部接口和類,為這些接口、類增加了泛型支持,從而可以在聲明集合變量、創建集合對象時傳入類型實參。

使用泛型的好處是什么?

????????它提供了編譯期的類型安全,確保你只能把正確類型的對象放入集合中,避免了在運行時出現ClassCastException。

????????在集合中沒有泛型時任何類型都能夠加入集合中,類型不安全,讀出來的時候還需要強轉。

????????在集合中有泛型時只有指定類型才能添加到集合中,類型是安全的,讀出來的時候不需要強轉,很便捷。

自定義泛型結構

泛型的聲明

Interface List<T> 和class GenTest<K,V> //其中,T,K,V,E不代表值,而是表示類型。這里使用任意字母都可以。 //常用T表示,是Type的縮寫。

泛型的實例化:

????????一定要在類名后面指定類型參數的值(類型)。如:???

List<String> strList= new ArrayList<String>(); Iterator<Customer> iterator = customers.iterator();

????????T只能是類,不能用基本數據類型填充。但可以使用包裝類填充,把一個集合中的內容限制為一個特定的數據類型,這就是generics背后的核心思想

? ? ? ?使用泛型的主要優點是能夠在編譯時而不是在運行時檢測錯誤。

自定義泛型類, 泛型接口

????????泛型類可能有多個參數,此時應將多個參數一起放在尖括號內。比如:<E1,E2,E3>

????????實例化后,操作原來泛型位置的結構必須與指定的泛型類型一致。

????????泛型不同的引用不能相互賦值。泛型如果不指定,將被擦除,泛型對應的類型均按照Object處理,但不等價于Object經驗:泛型要使用一路都用。要不用,一路都不要用。

????????如果泛型結構是一個接口或抽象類,則不可創建泛型類的對象。泛型的指定中不能使用基本數據類型,可以使用包裝類替換。

????????在類/接口上聲明的泛型,在本類或本接口中即代表某種類型,可以作為非靜態屬性的類型、非靜態方法的參數類型、非靜態方法的返回值類型。但在靜態方法中不能使用類的泛型。

????????異常類不能是泛型的

????????父類有泛型,子類可以選擇保留泛型也可以選擇指定泛型類型:

??? ??? 子類不保留父類的泛型:按需實現

??????? ??? 沒有類型擦除

??????? ??? 具體類型

??? ??? 子類保留父類的泛型:泛型子類

??????? ??? 全部保留

??????? ??? 部分保留

子類除了指定或保留父類的泛型,還可以增加自己的泛型

自定義泛型方法

????????方法,也可以被泛型化,不管此時定義在其中的類是不是泛型類。在泛型方法中可以定義泛型參數,此時,參數的類型就是傳入數據的類型。???

/*** 泛型方法的格式* [訪問權限] <泛型> 返回類型 方法名([泛型標識 參數名稱])拋出的異常* 泛型方法聲明泛型時也可以指定上限**/public class DAO {public<E> E get(intid, E e) {E result= null;return result;}}

泛型和子類繼承

??? 讓我們測試一下我們對泛型的理解。下面的代碼片斷合法么?

List<String> ls = new ArrayList<String>(); //1 List<Object> lo = ls; //2

????????第1 行當然合法,但是這個問題處在于第2 行。這產生一個問題:一個String 的List 是一個Object 的List 么?大多數人的直覺是回答: “當然!”。因為乍看起來String是一種Object,所以List<String>應當可以用在需要List<Object>的地方,但是事實并非如此。真這樣做的話會導致編譯錯誤。

??? 好,在看下面的幾行???

lo.add(new Object()); // 3 String s = ls.get(0); // 4: 試圖把Object 賦值給String

??? 這里,我們使用lo 指向ls。我們通過lo 來訪問ls,一個String 的list。我們可以插入任意對象進去。結果是ls 中保存的不再是String。當我們試圖從中取出元素的時候,會得到意外的結果。java 編譯器當然會阻止這種情況的發生。第2 行會導致一個編譯錯誤。總之,如果Foo 是Bar 的一個子類型(子類或者子接口),而G 是某種泛型聲明,那么G<Foo>是G<Bar>的子類型并不成立!!

????????如果你再深一步考慮,你會發現Java這樣做是有意義的,因為List<Object>可以存儲任何類型的對象包括String, Integer等等,而List<String>卻只能用來存儲Strings。 

通配符(Wildcards)

????????考慮寫一個例程來打印一個集合(Collection)中的所有元素。下面是在老的語言中你可能寫的代碼:

void printCollection(Collection c) {Iterator i = c.iterator();for (int k = 0; k < c.size(); k++) {System.out.println(i.next());} }下面是一個使用泛型的幼稚的嘗試(使用了新的循環語法):void printCollection(Collection<Object> c) {for (Object e : c) {System.out.println(e);} }

??????????一個集合,它的元素類型可以匹配任何類型。顯然,它被稱為通配符。我們可以寫:

void printCollection(Collection<?> c) {for (Object e : c) {System.out.println(e);} }

????????現在,我們可以使用任何類型的collection 來調用它。注意,我們仍然可以讀取c 中的元素,其類型是Object。這永遠是安全的,因為不管collection 的真實類型是什么,它包含的都是Object。但是將任意元素加入到其中不是類型安全的

Collection<?> c = new ArrayList<String>(); c.add(new Object()); // 編譯時錯誤

?????????因為我們不知道c 的元素類型,不能添加對象。add 方法有類型參數E 作為集合的元素類型。我們傳給add 的任何參數都必須是一個未知類型的子類。因為我們不知道那是什么類型,所以我們無法傳任何東西進去。唯一的例外是null,它是所有類型的成員。另一方面,我們可以調用get()方法并使用其返回值。返回值是一個未知的類型,但是我們知道,它總是一個Object

有限制的通配符(Bounded Wildcards)

????????限定通配符和非限定通配符。List<? extends T>和List <? super T>這兩個List的聲明都是限定通配符的例子:

????????List<? extends T>可以接受任何繼承自T的類型的List.

????????List<? super T>可以接受任何T的父類構成的List。例如List<? extends Number>可以接受List<Integer>或List<Float>????????

泛型方法

????????考慮寫一個方法,它用一個Object 的數組和一個collection 作為參數,完成把數組中所有object 放入collection 中的功能。下面是第一次嘗試:

static void fromArrayToCollection(Object[] a, Collection<?> c) {for (Object o : a) {c.add(o); // 編譯期錯誤} }

???????把對象放進一個未知類型的集合中。辦法是使用generic methods就像類型聲明,方法的聲明也可以被泛型化——就是說,帶有一個或者多個類型參數

static <T> void fromArrayToCollection(T[] a, Collection<T> c){for (T o : a) {c.add(o); // correct} }

我們可以使用任意集合來調用這個方法,只要其元素的類型是數組的元素類型的父類。

Object[] oa = new Object[100];Collection<Object> co = new ArrayList<Object>();fromArrayToCollection(oa, co);// T 指ObjectString[] sa = new String[100];Collection<String> cs = new ArrayList<String>();fromArrayToCollection(sa, cs);// T inferred to be StringfromArrayToCollection(sa, co);// T inferred to be ObjectInteger[] ia = new Integer[100];Float[] fa = new Float[100];Number[] na = new Number[100];Collection<Number> cn = new ArrayList<Number>();fromArrayToCollection(ia, cn);// T inferred to be NumberfromArrayToCollection(fa, cn);// T inferred to be NumberfromArrayToCollection(na, cn);// T inferred to be NumberfromArrayToCollection(na, co);// T inferred to be ObjectfromArrayToCollection(na, cs);// compile-time error}static <T> void fromArrayToCollection (T[] a, Collection<T> c) {for (T o : a) {c.add(o); // correct}}

????????注意,我們并沒有傳送真實類型參數(actual type argument)給一個泛型方法。編譯器根據實參為我們推斷類型參數的值。它通常推斷出能使調用類型正確的最明確的類型參數。

總結

以上是生活随笔為你收集整理的java基础知识(七)-- 泛型(Generics )的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。