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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java基础-泛型举例详解

發(fā)布時間:2023/12/13 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java基础-泛型举例详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

泛型

  泛型是JDK5.0增加的新特性,泛型的本質(zhì)是參數(shù)化類型,即所操作的數(shù)據(jù)類型被指定為一個參數(shù)。這種類型參數(shù)可以在類、接口、和方法的創(chuàng)建中,分別被稱為泛型類、泛型接口、泛型方法。

一、認識泛型

  在沒有泛型之前,通過對類型Object的引用來實現(xiàn)參數(shù)的"任意化",但"任意化"帶來的缺點是需要顯示的強制類型轉(zhuǎn)換,此種轉(zhuǎn)換要求開發(fā)者對實際參數(shù)類型預(yù)知的情況下進行,對于強制轉(zhuǎn)換錯誤的情況,編譯器可能不會提示錯誤,但在運行時會出現(xiàn)異常,這是一個安全隱患。

  舉例:不使用泛型實現(xiàn)參數(shù)化類型

1 package generic; 2 3 public class NoGeneric { 4 private Object ob; //定義通用類型成員 5 public NoGeneric(Object ob) { 6 this.ob = ob; 7 } 8 public Object getOb() { 9 return ob; 10 } 11 public void setOb(Object ob) { 12 this.ob = ob; 13 } 14 public void showType() { 15 System.out.println("實際類型是:"+ob.getClass().getName()); 16 } 17 } 18 19 package generic; 20 21 public class NoGenericDemo { 22 23 public static void main(String[] args) { 24 // TODO 自動生成的方法存根 25 //定義類NoGener的一個Integer版本 26 NoGeneric intob = new NoGeneric(new Integer(66)); 27 intob.showType(); 28 int i = (Integer)intob.getOb(); 29 System.out.println("value="+ i); 30 System.out.println("-----------------------------"); 31 //定義類NoGeneric的一個String版本 32 NoGeneric strob = new NoGeneric(new String("hello")); 33 strob.showType(); 34 String s = (String)strob.getOb(); 35 System.out.println("value="+ s); 36 } 37 }

?  執(zhí)行結(jié)果為:

實際類型是:java.lang.Integer value=66 ----------------------------- 實際類型是:java.lang.String value=hello

?

?

?  上面的實例有兩點需要注意:首先如下語句

String s = (String)strob.getOb();

?

  在使用時必須明確指定返回對象需要被強制轉(zhuǎn)化的類型為String,否則無法編譯通過;其次,由于intob和strob都屬于NoGeneric的類型,假如執(zhí)行如下語句

intob = strob;

?

  此種賦值,語法上是合法的,而在語義上是錯誤的,對于這種情況,只有在運行時才會出現(xiàn)異常,使用泛型就不會出現(xiàn)上述錯誤,泛型的好處就是在編譯期 檢查類型,捕捉類型不匹配錯誤,并且所有強制轉(zhuǎn)換都是自動和隱式的,提高代碼的重用率.

  舉例 2:使用泛型使用泛型實現(xiàn)參數(shù)實例化類型

package generic;public class Generic<T> {private T ob; //定義泛型成員變量 public Generic(T ob) {this.ob = ob;}public T getOb() {return ob;}public void setOb(T ob) {this.ob = ob;}public void showType() {System.out.println("實例類型為:" + ob.getClass().getName());} }package generic;public class GenericDemo {public static void main(String[] args) {// TODO 自動生成的方法存根//定義泛型Generic的一個Integer的版本Generic<Integer> intob = new Generic<Integer>(88);intob.showType();int i = intob.getOb();System.out.println("value=" + i);System.out.println("----------------------");//定義泛型Generic的一個String版本Generic<String> strob = new Generic<String>("hello");strob.showType();String s = strob.getOb();System.out.println("value=" + s);} }

  運行結(jié)果為:

實例類型為:java.lang.Integer value=88 ---------------------- 實例類型為:java.lang.String value=hello

?

  在引入泛型的前提下,如果再次執(zhí)行

intob = strob;

?

  將提示錯誤,編譯無法通過

二、泛型定義

  泛型的語法可歸納為

class class-name <type-param-list>{//......}

?

  實例化泛型的語法為:

class-name <type-param-list> obj = new class-name<type-param-list>(cons-arg-list);

?

  type-param-list用于指明當(dāng)前泛型類可接受的類型參數(shù)占位符的個數(shù); ? 如:

class Generic<T>{//......}

?

  這里的T是類型參數(shù)的名稱,并且只允許傳一個類型參數(shù)給Generic類,在創(chuàng)建對象時,T用作傳遞 給Generic的實際類型的占位符,每當(dāng)聲明類型參數(shù)時,只需用目標(biāo)類型替換T即可. ? 如:

Generic <Integer> intob;

?

  聲明對象時占位符T用于指定實際類型,如果傳遞實際類型為Integer,屬性ob就是Integer類型,類型T還可以指定方法的返回類型 ? ? 如:

public T getOb(){return ob; }

?  理解泛型有三點需要注意:

    1、泛型的類型參數(shù)只能為類類型(包括自定義類),不能是基本數(shù)據(jù)類型。

    2、同一種泛型可以對應(yīng)多個版本(因為類型參數(shù)時不確定的)、不同版本的泛型類實例是不兼容的。

    3、泛型的類型參數(shù)可以有多個。

    注意 ? 根據(jù)慣例,泛型類定義時通常使用一個唯一的大寫字母表示一個類型參數(shù).

三、有界類型

?  定義泛型類時,可以向類型參數(shù)指定任何類型信息,特別是集合框架操作中,可以最大限度地提高適用范圍,但有時候需要對類型參數(shù)的取值進行一定程度的限制,以使數(shù)據(jù)具有可操作性.

   為了處理這種情況,java提供了有界類型,.在指定類型參數(shù)時可以使用extends關(guān)鍵字限制此類型參數(shù)代表的類必須是繼承自指定父類或父類本身.

  使用extends關(guān)鍵字實現(xiàn)有界類型泛型類的定義

package generic;public class BoundGeneric<T extends Number> {//定義泛型數(shù)組 T[] array;public BoundGeneric(T[] array) {this.array = array;}//計算總和public double sum() {double sum = 0.0;for(T t : array) {sum = sum + t.doubleValue();}return sum;} }

?

  BoundGeneric類的定義中,使用extends將T的類型限制為Number類及其子類,故可以再定義過程中調(diào)用Number類的doubleValue方法,現(xiàn)在分別指定Integer,double,String類型作為類型參數(shù),測試BoundGeneric:

package generic;public class BoundGenericDemo {public static void main(String[] args) {// TODO 自動生成的方法存根//使用整形數(shù)組構(gòu)造泛型對象Integer[] intArray = {1, 2, 3, 4};BoundGeneric<Integer> iobj = new BoundGeneric<Integer>(intArray);System.out.println("iobj的和為:" + iobj.sum());//使用Double型數(shù)組構(gòu)造泛型對象Double[] douArray = {1.2, 2.3, 3.4, 4.5};BoundGeneric<Double> dobj = new BoundGeneric<Double>(douArray);System.out.println("dobj的和為:" + dobj.sum());String[] strArray = {"str1","str2"};//下面的語句將會報錯,String不是Number的子類//BoundGeneric<String> sobj = new BoundGeneric<String>(strArray); } }

?

  運行結(jié)果為:

iobj的和為:10.0 dobj的和為:11.4

  注:在使用extends(如:T extends someClass)聲明的泛型類進行實例化時允許傳遞的參數(shù)類型為:如果someClass是類,可以傳遞someClass本身及其子類;如果someClass接口可以傳遞實現(xiàn)接口的類

四、通配符

  首先在說通配符之前先看一下這段代碼:使用前面定義的Generic類.

package generic;public class WildcarDemo {public static void func(Generic <Object> g) {//... }public static void main(String args[]) {Generic <Object> obj = new Generic<Object>(12);func(obj);Generic<Integer> iobj = new Generic<Integer>(12);//這里講產(chǎn)生一個錯誤:類型 WildcarDemo 中的方法 func(Generic<Object>)對于參數(shù)(Generic<Integer>)不適用//func(iobj); } }

?

  上述代碼的func()方法的創(chuàng)建意圖是能夠處理各種類型參數(shù)的Generic對象,因為Generic是泛型,所以在使用時需要為其指定具體的參數(shù)化類型Object,看似不成問題,

  但在

func(iobj);

?

  處產(chǎn)生一個編譯錯誤,因為func定義過程中以明確聲明的Generic的類型參數(shù)為Object,這里試圖將Generic<Integer>類型的對象傳遞給func()方法,類型不匹配導(dǎo)致編譯錯誤.這種情況可以使用通配符解決.通配符由"?"來表示,它代表一個未知類型

package generic;public class WildcarDemo2 {public static void func(Generic <?> g) {//... }public static void main(String args[]) {Generic<Object> obj = new Generic<Object>(12);func(obj);Generic<Integer> iobj = new Generic<Integer>(12);func(iobj);} }

?

  上述代碼,在采用了通配符后語句將無誤的編譯,運行.

  在通配符使用的過程中,也可通過extends關(guān)鍵字限定通配符的界定的類型參數(shù)的范圍.

package generic;public class WildcarDemo3 {public static void func(Generic <? extends Number> g) {//... }public static void main(String args[]) {Generic<Object> obj = new Generic<Object>(12);//這里將產(chǎn)生一個錯誤:類型 WildcarDemo3 中的方法 func(Generic<? extends Number>)對于參數(shù)(Generic<Object>)不適用//func(obj); Generic<Integer> iobj = new Generic<Integer>(12);func(iobj);} }

?

五、泛型的局限性

  java并沒有真正實現(xiàn)泛型,是編譯器在編譯的時候在字節(jié)碼上做了手腳(稱為擦除). 這種實現(xiàn)理念在成java泛型本身有很多漏洞, 為了避免這些問題java對泛型的使用上做了一些約束,但不可避免的還是有一些問題存在.多數(shù)的限制都是由類型擦除引起的.

  1、泛型類型不能被實例化

public class Gen<T>{T ob;public Gen(){ob = new T();} }

?

  Gen<T>構(gòu)造器是非法的,類型擦除將變量T替換成Object,但這段代碼的本意肯定不是調(diào)用new Object().類似:如

public <T> T[]build (T[] a){T [] array = new T[2];
  //... }

?

  類型擦除會讓這個方法總是構(gòu)造一個Object[2]數(shù)組,但是可以通過調(diào)用Class.newInstance和Array.newInstance方法,利用反射構(gòu)造泛型對象和數(shù)組

2、數(shù)組

  不能實例化數(shù)組如:

T[] vals; vals = new T[10];

?

  因為T在運行時時不存在的,編譯器無法知道實際創(chuàng)建那種類型的數(shù)據(jù).

  其次,不能創(chuàng)建一個類型特定的泛型引用的數(shù)組 ? ?如:

Gen<String> []arrays = new Gen<String>[100];

?

  上面的代碼會損害類型安全

  如果使用通配符,就可以創(chuàng)建泛型類型的引用數(shù)組

Gen<?> []arrays = new Gen<?>[10];

?

3、怒能用類型參數(shù)替換基本類型

  因為擦除類型后原先的類型參數(shù)被Object或者限定類型替換,而基本類型是不能被對象所存儲的,可以使用基本類型的包裝類來解決此問題

4、異常

  不能拋出也不能捕獲泛型類的異常對象,使用泛型類來擴展Throwable也是非法的. 如:

public class GenericException <T> extends Exception{//泛型類無法繼承Throwable }

?

  不能再catch子句中使用類型參數(shù),例如下面的方法將不能編譯

public static <T extends Throwable> void doWork(Class<T> t) {try {//...}catch(Throwable realCause) {//...}

?

  但是在異常聲明時可以使用類型參數(shù),如:

public static <T extends Throwable> void doWork(T t) throws T {try {//...}catch(Throwable realCause) {throw t;}}

?

5、靜態(tài)成員

  不能在靜態(tài)變量或者靜態(tài)方法中引用類型參數(shù) ?如:

public class Gen<T>{static T ob;static T getOb() {return ob;} }

?這些均參考自“Java SE程序設(shè)計”,算是做個筆記,以后忘了可以翻閱一下,寫在自己的隨筆中,也希望可以幫助更多的人。如有侵權(quán),請聯(lián)系本人刪除

?

轉(zhuǎn)載于:https://www.cnblogs.com/Mykebai/p/9123749.html

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。