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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java:高级之泛型概念引入,泛型可以设置多个类型参数,泛型继承和泛型接口实现,限制泛型可用类型,泛型通配的方式,泛型方法,泛型方法限制泛型可用类型

發布時間:2025/4/5 java 13 豆豆

目錄頁

? ? ? ? 泛型簡介

? ? ? ? 泛型類

? ? ? ? 限制泛型可用類型

? ? ? ? 類型通配聲明

? ? ? ? 泛型方法

問題引入

? ? ? ? 如果我們需要產生多個對象,每個對象的邏輯完全一樣,只是對象內的成員變量的類型不同。那我們如何去做?

我們新建一個工程

做一個構造方法????????public Cls1(int a){
?? ??? ?????????????????????????????????this.a =a;
?? ?????????????????????????????????????????}

然后我們實例化這個方法的時候,給他傳一個10????????Cls1 cls1 = new Cls1(10);

然后我們輸出cls1 里面的getData()????????????????System.out.println(cls1.getData());

?運行結果

?同樣的我們在做一個類,唯一的區別,所有的東西都一樣,但是它a變成了????????String a;

?運行結果

你會發現有兩個類,這兩個類的邏輯完全一樣,所謂的邏輯就是里面的一些方法,包括構造方法,只是成員變量的類型不同

?那比如我們現在要做了double 類型的,是不是還得專門為double 創建一個類呀?

? ? ? ? ??

問題解決

? ? ? ? 創建多個類文件,給每個類中的成員變量設置指定的數據類型

? ? ? ? ? ? ? ? 缺點:這種方法會導致類的膨脹,重用性太差。

? ? ? ? 創建一個類文件,給這個類中的成員變量設置Object數據類型。

? ? ? ? ? ? ? ? 缺點:編譯的時候正常,但運行的時候可能會異常

?創建多個類文件,給每個類中的成員變量設置指定的數據類型:

這樣整個業務場景下來,整形一個,小數一個,字符一個,甚至里面會集成一些其他的類。

創建一個類文件,給這個類中的成員變量設置Object數據類型。:

我們會發現整形int ,打開它的類型繼承

?你會發現Object是所有類型的父類

這種情況下我們完全可以把這兩個刪掉一個,

然后我們把Cls2改成Cls1? ? ? ? 第21行

發現沒寫錯,可是還報錯? ? ? ? 錯誤提示:? ? ?The constructor Cls1(int) is undefined

?發現是版本的問題

我們右擊,然后選擇properties

?然后看到JDK那行了嘛?

?

把對勾去掉

然后選擇1.5版本往后的點擊ok

?這個時候就沒有報錯了

?運行一下

?但是他有一個不太好的地方

這個Object導致整個類對這個變量的屬性很模糊

可能會產生某些錯誤,

假如我現在輸出“冰糖李子”,編碼過程中誤操作了,把“冰糖李子”這個字符串強制轉換成整型數,你會發現編譯的時候是ok 的

但是運行的時候會出現異常,類型轉化異常

難免我們在操作過程中,隨著代碼量的增大,對里面的object的類型模糊不清晰,導致你程序員在編寫代碼的時候,做了一個誤判,做了一個錯誤的轉換,導致程序崩潰

面向于 這種情況發生,我們有一個非常好的解決辦法,就是泛型

一、泛型簡介? ? ? ? JDK1.5之后引入?

? ? ? ? 泛型可以在編譯的時候檢查類型安全,并且所有的強制轉換都是自動和隱式的

? ? ? ? 泛型的原理就是“類型的參數化”,即把類型看做參數。也就是說把所要操作的數據類型看做參數,就像方法的形式參數是運行時傳遞的值的占位符一樣。

? ? ? ? 簡單的說,類型變量扮演的角色就如同一個參數,它提供給編譯器用來類型檢查的信息。

? ? ? ? 泛型可以提高代碼的擴展性和重用性

那么泛型怎么做?

示例----泛型類

? ? ? ? public? class GenClass<T>{

? ? ? ? ? ? ? ? private ??T? obj;

????????

? ? ? ? ? ? ? ? public? GenClass(T? ?obj){

? ? ? ? ? ? ? ? ? ? ? ? this.obj = obj;

????????????????}? ? ? ? ?

? ? ? ? ? ? ? ? public? T? getobj(){

? ? ? ? ? ? ? ? ? ? ? ? return obj;

????????????????}

? ? ? ? ? ? ? ? public? void? ?setobj(T? obj){

? ? ? ? ? ? ? ? ? ? ? ? this .obj? = obj;

????????????????}

}

泛型的意思就是就是在class后面添加一個<T>,用T去替代里面未名的數據類型

比如說我們的代碼可以在Cls1后面加上<T>,用一個T來表示

然后new 的時候要把這個東西用上,你在實例化的時候呈現,他是一個整形

Cls1<Integer> cls1= new Cls1<Integer>(10);

同樣使用cls2的時候,落地的時候,我讓他都是字符串

Cls1<String> cls2 = new Cls1<String>("冰糖李子");

?運行結果

我們用<T>替代了剛才寫的Object,在使用的時候,在程序員編碼的過程當中,實例化類的時候,在<>里面,去告訴操作系統,包括程序員看代碼的時候更具象的把他表達出來

這就叫做泛型

泛型可以在編譯的時候檢查類型安全,并且所有的強制轉換都是自動和隱式的

當你轉換出現問題的時候,你硬要把string轉化成Integer,他就會報錯,

剛才我們用object的時候它沒有任何的報錯,

只是在程序運行的時候出現類型轉換異常

(這就是泛型引入的除了程序員可讀之外,還有個好處就是防止你的誤操作,誤轉換)

Cannot cast from String to Integer

?? ? ? ? 泛型的原理就是“類型的參數化”,即把類型看做參數。也就是說把所要操作的數據類型看做參數,就像方法的形式參數是運行時傳遞的值的占位符一樣。:

我們習慣了函數調用,習慣了傳參public Cls1(T a),

那實際上類型也可以以參數的形式傳過來,為了區別我們用來了<>

我們在這個類初始化,實例化的時候?? ?Cls1<Integer> cls1= new Cls1<Integer>(10);

我們直接把泛型類里面的,涉及到泛型的位置,用Integer替代進去

也就是說Cls1類里面的? a變量的的類型,????????T a;

是根據我們真正實例化的時候,用<>的方式傳參過去的,來確定里面a的類型

,同樣的一個類,你在使用實例化的時候,給泛型傳的類型不一樣,這個類最后體現的結果也是不一樣的

????????????????????????????????Cls1<Integer> cls1= new Cls1<Integer>(10);
?? ??? ??????????????????????????? ?System.out.println(cls1.getData());
?? ??? ??????????????????????????? ?Cls1<String> cls2 = new Cls1<String>("冰糖李子");
?? ??? ??? ?????????????????????????????????System.out.println(cls2.getData());

?二、泛型類及特點

? ? ? ? 1、泛型的類型參數可以是泛型類

? ? ? ? 2、泛型類可以同時設置多個類型參數

? ? ? ? 3、泛型類可以繼承泛型類

? ? ? ? 4、泛型類可以實現泛型接口

?泛型的類型參數可以是泛型類:

也就是說你這個<T>除了普通變量Integer? ?和String 外,他也能接受是個泛型

泛型類可以繼承泛型類:

跟我們普通類的繼承是一樣的,當然你泛型可以在繼承過程中實現多個類型參數

你的父類型是個泛型,他里面只有一個<T>,你完全可以除了<T>,多一個<K>?呀,<T2>等等。

一般我們泛型用的<T>,不是寫死的 ,就像形參的名字,你愿意起什么都可以的,

按照程序員編碼習慣,一般是<T>呀,<K>,<B>呀,經常用的幾種寫法

泛型類可以實現泛型接口:

這個繼承和實現,和我們普通類的繼承和實現沒有很大的區別,唯一的區別就是體現在參數上面,和泛型上面

泛型類可以同時設置多個類型參數:

現在再做一個類Cls2,多個參數用,隔開????????class? Cls2<T,T2>

構造方法????????????????????????public Cls2(T a,T2 b){
?? ??????????????????????????????????????????? ?this.a =a;

? ? ? ? ????????????????????????????????????????this.b =b;
?????????????????????????????????????????? ?}

有兩個變量,????????????????T a;
?? ?????????????????????????????????T2 b;

這兩個變量的具體類型為止

同樣的b的類型是T2,????????public T getData(){
?? ??? ?????????????????????????????????????????return a;
?? ?????????????????????????????????????????}
?? ?
?? ?????????????????????????????????????????public T2 getData2(){
?? ??????????????????????????????????????????????????? ?return b;
?????????????????????????????????????????????????? ?}

我們在真正做他的時候,<>里面的順序一樣,構造方法要傳參

? ?

?運行結果

? ? ? ? ? ?

?這面要注意一個問題,比如說我現在有一個Cls4,兩個泛型我們都是整型數

這面顯示一個錯誤?

he constructor Cls2<Integer,Integer>(int, String) is undefined

你這面都寫integer,但是他會認定你傳進來的構造方法是一個字符串,所以他會失敗

?我改成10就OK啦

?

?那么我們可以把上面兩個整型數拿來相加嘛?

運行結果?

?暫時看到編譯是ok 的,加也是可以正常加的

?那如果一個是Integer 一個是String呢

數據類型不同的時候相加,看結果

?

運行結果????????

也能加????????

用System.out.println可加的????????????????

但是會給人家錯誤的認為,感覺不同的數據類型都可以拿來加,????????????????????????????????????????

但是你要知道System.out.println這面的加號是起到一個連接的作用????????

?如果我們單獨給他拎出來,他會出現一個什么樣的情況呢?

????????int sum = 0;
?? ??? ??? ?sum = cls4.getData()+cls4.getData2();
?? ??? ??? ?System.out.println(sum);
?? ??? ??? ?

?

?運行結果

這樣子寫也行?

泛型的類型參數可以是泛型類:

Cls1<Integer> cls1= new Cls1<Integer>(10);里面也可以放入泛型

比如說里面就是Cls1,Cls1他就是個泛型,這邊我用Integer給他確認下來

????????????????????????Cls1<Cls1<Integer>> cls1

另一面也一樣

這面出現問題是因為不能寫10,

?因為他應該是Cls1<Integer>的實例化?? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

泛型類里面的類型還是個泛型,你new的時候和前面一樣,這面的構造方法呢?

?構造方法傳過來的時候 ,T不就變成Cls1<Integer>

我們在輸出的時候,System.out.println(cls1.getData());

這個Data,get出來是一個泛型

因為Cls1他是最外面的那一層,你獲得出來的應該是Cls1<Integer>,

Cls1<Cls1<Integer>> cls1= new Cls1<Cls1<Integer>>(new Cls1<Integer>(10));
? ? ?

這個Cls1<Integer>又是一個類,你如果訪問到a,你還得getData一次

????????System.out.println(cls1.getData().getData());

這個時候我們才能把10抓出來

?運行結果

泛型類可以繼承泛型類:

我現在的Cls2和Cls1是重復的呀,這樣寫也是一種浪費?

可以 ????????class Cls2<T,T2> extends Cls1<T>,繼承過來兒子比父親多點特性,是ok的,

就是構造方法這面我們需要做一些修改

錯誤提示:????????Implicit super constructor Cls1<T>() is undefined. Must explicitly invoke another constructor

因為他要調用父親的?????????? ?super(a);? ? ? ? 你在子的構造方法中,調用父親的構造方法來構造自己

剩下的一項,? ?this.b=b; ? ? 作為數據的初始化

?可以把父類有的去掉

?然后我們使用一下

Cls2<Integer,String> cls = new Cls2<Integer,String>(100,"冰糖李子");

用法還是一樣的,就是我們在構造Cls2的時候,不要寫那么多代碼,一些東西是從Cls1繼承過來的?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

那如果他是繼承的話,有一些函數,比如說???????????void printInfo();????????假設他現在是個泛型,

同時又是一個抽象的方法? ?? ? ? ? ?????????????????abstract?void printInfo();?

這邊是一個抽象帶有泛型的類????????abstract class Cls1<T>? ? ? ? 也是ok的

也是遵循以前繼承的道理,你要把里面 的printInfo()實現出來

錯誤提示:???????? Multiple markers at this line
?? ?????????????????????????- Cannot instantiate the type?
?? ? ????????????????????????Cls1<Cls1<Integer>>

因為abstract class Cls1<T>? ? ? ? 是一個抽象

抽象類是不能初始化的,可以去掉? ? 第39行,第40行

?????代碼如下

?

?運行結果

?泛型類可以實現泛型接口:

我們比如說再來一個interface cls3<T>? ? ? ? 也是泛型

里面有一個抽象方法

這是一個接口

跟以前的寫法也是一樣的,

以前的寫法? 是? ? ? 沒有<T>,然后

????????????????????????????????????????interface cls3
????????????????????????????????????????????????{

?? ?????????????????????????????????????????????????abstract void printInfoCls3(String t);
????????????????????????????????????????????????}

這就是我們以前說的接口,無非在這個接口上加了一個泛型

也就是這個抽象方法,可以實現,輸出整型數,字符串都是ok的

?那我們的cls2可以繼承cls1

?Cls2也可以implements這個接口

?class Cls2<T,T2> extends Cls1<T> implements Cls3<T>

既然你要實現接口的話,就要實現接口里面的方法

?我們在使用Cls2的時候? ? ? ? 第53行

????????????????????????cls.printInfoCls3(100);

雖然Cls2那面寫的都是T,但是??????public Cls2(T a,T2 b){
?? ??? ?????????????????????????????????????????????????super(a);
?? ??????????????????????????????????????????????????????????? ?this.b=b;
?? ?????????????????????????????????????????????????}

這兩個T不一樣????????????????public void printInfoCls3(T t) {
?? ??????????????????????????????????????????? ?// TODO Auto-generated method stub
?? ??? ?????????????????????????????????????????System.out.println(t);

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }

下面這個T是隸屬于????????interface Cls3<T>這個接口的,取決于你傳遞進來是什么數據

上面的那個T是????????Cls2<Integer,String> cls = new Cls2<Integer,String>(100,"冰糖李子");里面的,它取決于你給他實例化的時候,設定的是具體的哪個參數

當然,剛好我們寫了Integer? ?和?? ?cls.printInfoCls3(100);? 里面的100

如果我們把????????cls.printInfoCls3(100); 改成字符串呢?? ? ? ? 第53行

錯誤提示:The method printInfoCls3(Integer) in the type Cls2<Integer,String> is not applicable for the arguments (String)? ? ? ? 不行了

所以說T如果產生某種沖突的話,也是不允許的

?你這時候即繼承了Cls1都叫T,又實現了這個接口,在這種情況下,你如果名字一樣

你要遵循在class Cls2<T,T2> extends Cls1<T> implements Cls3<T>

????????下面所有的T表示的都是同一種類型

不然他這面會產生類型上的沖突

?

?這種情況下改變一個T3試試

?我把class Cls2<T,T2,T3> extends Cls1<T> implements Cls3<T3>

里面的T3去掉可以嗎?? ? ? ? 第22行

也不行,因為public void printInfoCls3(T3 t)

必須在class Cls2<T,T2,T3> extends Cls1<T> implements Cls3<T3>

被包含

?你要支持T3,你就要做出一系列的修改

Cls2<Integer,String> cls = new Cls2<Integer,String>(100,"冰糖李子");你要跟T3綁定起來

而且必須是一個String

如果這時候你把?cls.printInfoCls3("測試");? ?改成cls.printInfoCls3(100);

也不行

?完整代碼

?

運行結果

?注意:泛型類可以實現泛型接口,

但是要注意,既要繼承又要實現接口的 時候,要保證它里面具備了這些泛型的占位符

三、限制泛型可用類型

????????在定義泛型類別時,默認在實例化泛型類的時候可以使用任何類型,但是如果想要限制使用泛型類型時,只能用某個特定類型或者是其子類型才能實例化該類型時,可以在定義類型時,使用extends關鍵字指定這個類型必須是繼承某個類,或者實現某個接口。

? ? ? ? 當沒有指定泛型繼承的類型或接口時,默認使用extends Object,所以默認情況下任何類型都可以做為參數傳入

? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ?

?當沒有指定泛型繼承的類型或接口時,默認使用extends Object,所以默認情況下任何類型都可以做為參數傳入:

這就是我們之前的做法

?

?系統在編譯它的時候是默認加了一個extends Object

你寫不寫它的效果是一樣的,也就是對T他沒有任何的限制,所以在使用它的時候任何類型都可以作為參數傳入

?

?那如果某種場景我們必須對這個T做一些監管,限制使用泛型類型,

可以使用extends關鍵字指定這個類型必須是繼承某個類,或者實現某個接口

如果我變成了????????abstract class Cls1<T extends String>

如果你這樣寫,你沒辦法給這面賦一個整型數的

?

?這個時候只能把

?? ?Cls2<Integer,String,String> cls = new Cls2<Integer,String,String>(100,"冰糖李子");

Integer? ? 變成? ?String類型? ? ? ? 這面的100也只能改成字符串

Cls2<String,String,String> cls = new Cls2<String,String,String>("","冰糖李子");

這就是我們說的限定了T,

?

?可以用繼承,可以用某個接口

我們添加一些具體的寫法進來

我要求這個T必須繼承Animal? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ??

一寫進來Cls2<String,String,String> cls = new Cls2<String,String,String>("","冰糖李子");

必須變成? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

Cls2<Dog,String,String> cls = new Cls2<Dog,String,String>(new Dog(),"冰糖李子");

?

?那如果我現在有一個接口,接口里面有一個抽象的方法? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
interface Move? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
{? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?? ?abstract void test();
}

如果你對于T做一些限制要求,必須要實現Move這個接口? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

我們以前實現接口是????????class A implements Move {? ? ? ? ? ? ??

????????????????????????????????????????????????}? ? ? ?這樣一個寫法

A這面去實現Move里面未實現的方法·? ? ? ? 叫做test

?如果這面也用Move的話? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

abstract class Cls1<T extends Move>? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

是用? extends? ? ? abstract class Cls1<T extends Move>? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

還是????implements?????abstract class Cls1<T implements Animal>? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

發現還是得用extends? ? ? abstract class Cls1<T extends Move>? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

注意他跟我們傳統的????????implements是不一樣的? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

?

?

?為什么????????abstract class Cls1<T extends Move>? ? ? ? ? ?多了extends?

因為他可能繼承某個類? ? ? ? ,或者限定了它實現某個接口? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

四、類型通配聲明

同一泛型類,如果實例化時給定的實際類型不同,則這些實例的類型是不兼容的,不能互相賦值。

????????Generic<Boolean> f1 = new Generic<Boolean>();

? ? ? ? Generic<Integer> f2 = new Generic<Integer>();

? ? ? ? f1 = f2;? ? ? ? ? //發生編譯錯誤

? ? ? ? Generic<Object> f= f1 ;? ? ? ? ?//f1和f類型并不兼容,發生編譯錯誤f=f2;

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//f2和f類型同樣不兼容,也會發生編譯錯誤

? ? ? ? 泛型類實例之間的不兼容性會帶來使用的不便。我們可以使用泛型類通配符(?)聲明泛型類的變量就可以解決這個問題。

新建一個工程

?現在有一個Cls1,實例化一下(記得抽象類不能實例化)

?同樣的我們再來一個c2,來一個Double類型的,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

然后我們讓c1 = c2;? ? ? ? 他是不允許的? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

錯誤提示????????Type mismatch: cannot convert from Cls1<Double> to Cls1<Integer>

不能把c2轉化為c1,因為Double和Integer是有區別的? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

?那如果我們現在有Object,行不行?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

更大的類,去做一些匹配? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

錯誤提示? ?Type mismatch: cannot convert from Cls1<Object> to Cls1<Integer>

他也是不行的? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

反過來也不行

類型通配聲明? ? ? ? 例子

? ? ? ? 泛型通配的方式

? ? ? ·? “?”代表任意一個類型? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ????????? Generic<Boolean>? f1 = new Generic<Boolean>();? ? ? ? ? ? ??

? ? ? ????????? Generic<?> f = f1;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ·和限制泛型的上限相似,同樣可以使用extends關鍵字限定通配符的上限? ? ? ? ? ? ??

? ? ? ????????? Generic<Dog> f1 = new Generic<Dog>();? ? ? ? ? ? ? ? ? ? ? ??

? ? ? ? ????????Generic<? extends Annimal> f =f1;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ?·?還可以使用super關鍵字將通配符類型限定為某個類型的下限

? ? ? ? ????????Generic <Animal> f1 = new Generic<Animal>();? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ????????Generic<? super Dog> f =f1;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

? ? ? ? ? ? ? ? ? ? ? ? //它必須是Dog 的父親

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

也就是說我們用一個<?? 就可以搞定了,我們聲明這個c3;

這個時候你會發現c3可以引用c1

?同樣的c3可以引用c2;

這個就是我們說的通配符,用?來表示

和限制泛型的上限相似,同樣可以使用extends關鍵字限定通配符的上限:

也就是說,你可以管理這個問號

比如說我們來個c4,我們c4這面要求是一個Dog

比如說我的c4里面的泛型是一個Dog

這種情況下我的c3可以等于c4,因為這個問號是通配所有的

?那如果對于問號管制的話,????????Cls1<? extends String> c3;

發現很多東西都不能用了,因為他必須是String 的子類或者String

?那如果我們把他改成Integer 呢?

發現只有c1這一條是可以的

?如果改成Animal?????????????????Cls1<? extends Animal> c3;呢?

1和2 不行,4是可以的,????????????????對?號產生了一定的范圍

只有它的上限是Animal 的時候才可以

?還可以使用super關鍵字將通配符類型限定為某個類型的下限:

比如我這面用super,就不行了,它必須是Animal的父親

?如果把這面改成一個Dog 呢?

?改成Animal也是可以的

? ? ?

?五、泛型方法

? ? ? ? 不僅類可以聲明泛型,類中的方法也可以聲明僅用于自身的泛型,這種方法叫做泛型方法。其定義格式為:

? ? ? ? 訪問修飾符? <泛型列表>? 返回類型? 方法名? (參數列表){

? ? ? ? ? ? ? ? 實現代碼

????????}

? ? ? ? 在泛型列表中聲明的泛型,可用于該方法的返回類型聲明、參數類型聲明和方法代碼中的局部變量的類型聲明

? ? ? ? 類中其他方法不能使用當前方法聲明的泛型

? ? ? ? 提示:是否擁有泛型方法,與其所在的類是否泛型沒有關系。要定義泛型方法,只需將泛型參數列表置于返回值前

?不僅類可以聲明泛型,類中的方法也可以聲明僅用于自身的泛型,這種方法叫做泛型方法。:

也就是說,這個泛型是屬于方法的,不是屬于類的,也就是說我們可以在普通類中去定義一個泛型方法。

類中其他方法不能使用當前方法聲明的泛型:

也就是說我這個泛型是有時效性的。它是有區域性的,有一個它的作用域,有點像局部變量。你在當前方法中有泛型列表,在其他方法中不能用

是否擁有泛型方法,與其所在的類是否泛型沒有關系。要定義泛型方法,只需將泛型參數列表置于返回值前:

也就是我們說的普通類可以有泛型方法

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??? ? ? ? ? ? ? ??

你有了泛型類,為何還要泛型方法呢?

新建一個工程

假設classA里面有一個泛型<T>

? ? ? ? ??

錯誤提示:Multiple markers at this line
?? ?- Syntax error, type parameters are only available if source level is 1.5 or?
?? ? greater

需要換到1.5版本以后的

找到這里?

?

?看見JDK那行了嘛

對勾去掉,換成1.5版本以后的

?然后就沒有錯誤提示了

?運行結果,可行

?那如果我在這里打印一個100呢?

編譯都通不過

錯誤提示:????????The method printInfo(String) in the type A<String> is not applicable for the arguments (int)

因為他要求你傳String,但是你的arguments是100

?等于說這個方法,

被里面的泛型給限制了????????????????class A<T>
???????????????????????????????????????????? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??? public void printInfo(T t){
?? ?????????????????????????????????????????????????????? ????????System.out.println(t);
?? ????????????????????????????????????????????????????????????}
????????????????????????????????????????????????????????}

那么泛型方法是什么意思呢?我不應該讓我的t ????????被你的類限制掉

比如說我現在有一個class? B

我可以把他聲明為普通的方法????????class B<T>

注意:泛型方法是????????

? 訪問修飾符? <泛型列表>? 返回類型? 方法名? (參數列表){

? ? ? ? ? ? ? ? 實現代碼

????????}

也就是說我的泛型列表可以放在返回類型的前面? ? ? ? void前面我放一個<T>

????????????????public <T> void printInfo(T t){
?? ??? ?????????????????????????System.out.println(t);
?????????????????????????? ?}

?

?運行結果

我們得出的結論,泛型方法更加靈活,它可以不受泛型類的約束

如果你泛型類在實例化的時候,確定了泛型的類型,以及你方法里面所有的東西? ?T??都被定死掉了

就出現了剛才我們的A ????????只能打哈哈,不能打1234

這個東西比我們以前做的方法的重載,更加的牛逼

?以前方法重載是什么意思呢?

????????????????public void print1(int a){
?? ??????????????????? ?System.out.println(a);
?????????????????? ?}

再來個char a 這就叫方法的重載

????????????????public void print1(char a){
?? ??????????????????????????????????? ?System.out.println(a);
?????????????????? ?}

? ? ? ??

你即便方法重載也要寫這么多遍

那泛型方法它的好處,比方法重載更加牛逼

不僅類可以聲明泛型,類中的方法也可以聲明僅用于自身的泛型,這種方法叫做泛型方法:

也就是我的T? ? ? ? ?第11行,只對我本方法有效

跟這個類class? B沒有關系,跟其他的方法也沒有關系

也就是說你能不能用到t????????呀?

錯誤提示:? t cannot be resolved to a variable

?當然泛型列表中的個數也可以做多個????????????????

????????public <T,T2> void printInfo(T t,T2 t2){
?? ??? ?????????????????System.out.println(t+t2);
?? ?????????}
?? ?

這其實也是個方法的重載,但是這面t2不讓加? ?

錯誤提示:he operator + is undefined for the argument type(s) T, T2

?分開寫呢?

?

?為什么不讓加呢?因為他如果在后面實例化,確定類型以后是可讓加的,

,你這面沒有實例化,它的方法類型是不確定的,不讓你亂加

?

?當然????????public <T,T2> void printInfo(T t,T2 t2){
?? ??? ?????????????????????????System.out.println(t);
?? ??? ?????????????????????????System.out.println(t2);
?? ?????????????????}

也是泛型方法,只是對????????????????public <T> void printInfo(T t){
?? ??? ?????????????????????????????????????????????????System.out.println(t);
?????????????????????????????????????????????????????????? ?}

做了重載

我們重載的意思是,返回值,跟這個名字一樣,參數列表可以不一樣

?在泛型列表中聲明的泛型,可用于該方法的返回類型聲明、參數類型聲明和方法代碼中的局部變量的類型聲明:

也就是說?????????? ?public <T,T2> void printInfo(T t,T2 t2){
?? ??????????????????????????? ?System.out.println(t);
?? ??????????????????????????????????? ?System.out.println(t2);
?????????????????????????????????? ?}
可以返回一個T? ??public <T,T2> T printInfo(T t,T2 t2){
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?System.out.println(t);
?? ???????????????????????????????????????? System.out.println(t2);
?? ??? ?
?? ??? ?????????????????????????????????????????return t;
? ? ? ? ?????????????????????????????????}

這樣子是可以的

?

類型聲明:????????public <T,T2> T printInfo(T t,T2 t2)
局部變量:?? ??????????? ?System.out.println(t);

五、泛型方法

? ? ? ? 什么時候使用泛型方法,而不是泛型類呢???

? ? ? ? ? ? ? ? 添加類型約束只作用于一個方法的多個參數之間,而不涉及類中的其他方法時。

? ? ? ? ? ? ? ? 施加類型約束的方法為靜態方法,只能將其定義為泛型方法,因為靜態方法不能使用其所在類的類型參數

? ? ? ? ? ? ? ? ? ? ?

? 添加類型約束只作用于一個方法的多個參數之間,而不涉及類中的其他方法時。:

我們不希望這個方法當中的數據類型被這個類給限制了,而是自由的我想打印什么,都可以,不被類的方法限制的時候

施加類型約束的方法為靜態方法,只能將其定義為泛型方法,因為靜態方法不能使用其所在類的類型參數:

類型約束:

也就是說????????public <T> void printInfo(T t)這個泛型T也可以進行類型的約束

? ??

? ?前面加上

????????????????????????class Animal
????????????????????????????????{?? ?
?????????????????????????????????? ?public void eat(){
?? ??? ?????????????????????????????????System.out.println("動物吃");
?? ????????????????????????????????????}
????????????????????????????????}

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????????? ??

? ? ? ? ? ? ? ? ? ? ? ? ? ? ?class Dog extends Animal
????????????????????????????????{
?? ?????????????????????????????????public void eat(){
?? ??????????????????????????????????? ?System.out.println("啃骨頭");
?? ?????????????????????????????????????????}
????????????????????????????????????????}

????????????????????????????????class Cat extends Animal
????????????????????????????????{
?? ?????????????????????????????????public void eat(){
?? ??? ?????????????????????????????????System.out.println("吃魚");
?? ?????????????????????????????????????????}
????????????????????????????????????????}

中間加上????

他必須是一個上限,是Animal的子類? ? ? ??

????????????????????????????public <T extends Animal> void printInfo2(T t){
?? ??????????????????????????????????????????? ?t.eat();
?? ?????????????????????????????????????????}

這就叫類型約束

這時候來個?????????? ?b.printInfo2("哈哈");? 可以嘛?

錯誤提示:Bound mismatch: The generic method printInfo2(T) of type B is not applicable for the?
?arguments (String). The inferred type String is not a valid substitute for the bounded?
?parameter <T extends Animal>

?

?這時候只能????????????????b.printInfo2(new Dog());
?? ??? ??? ?????????????????????????b.printInfo2(new Cat());
?? ??? ??? ?????????????????????????b.printInfo2(new Animal());

也就是我們之前講的對泛型<T>的限制,放在泛型方法里面是同樣適用的

?

?運行結果

?靜態方法:

我們比如把

public <T extends Animal> void printInfo2(T t)變成

public static <T extends Animal> void printInfo2(T t)

警告:? ? ? ? 第71行,第72行,第73行

The static method printInfo2(Dog) from the type B should be accessed in a static way

?

?出現這種情況,完全可以?? ?B.printInfo2(new Dog());

靜態方法就是要求我們這樣做

不用非得實例化,類的名字加上方法名,做一個靜態的調用

靜態方法不能使用其所在類的類型參數:

因為靜態方法本身就是和這個類脫離的

注意:這個T會被重置,編譯的時候

第33行的T? ? ? public <T> void printInfo(T t)?????????到最后會變成object

第44行的T? ? ?public static <T extends Animal> void printInfo2(T t)??????????????????到最后會變成Animal

?

?注意:不管你是泛型方法還是普通方法,你不能搞一摸一樣的

Duplicate method print1(int) in type B

?

總結

以上是生活随笔為你收集整理的Java:高级之泛型概念引入,泛型可以设置多个类型参数,泛型继承和泛型接口实现,限制泛型可用类型,泛型通配的方式,泛型方法,泛型方法限制泛型可用类型的全部內容,希望文章能夠幫你解決所遇到的問題。

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