泛型的介紹和使用二

2021-09-24 18:38:30 字數 3912 閱讀 9007

為什麼要適用型別繫結?

public inte***ce comparable
但如果我們直接通過函式來比較型別的大小,肯定會報錯,因為編譯器根本不知道什麼型別?又怎麼比較呢?

所以需要讓編譯器知道是什麼型別,這就是型別繫結的用處了。

定義形式:

此定義表示t應該是boundingtype的子型別(subtype)。t和boundingtype可以是類,也可以是介面。另外注意的是,此處的」extends「表示的子型別,不等同於繼承。

型別繫結有兩個作用:1、對填充的泛型加以限定 2、使用泛型變數t時,可以使用boundingtype內部的函式。

(1)繫結介面

public inte***ce comparable

//新增上extends comparable之後,就可以comparable裡的函式了

public static t min(t...a)

}return smallest;

}

這裡的泛型直接繫結comparable介面,通過傳進去的型別陣列a,然後比較每一項的大小,最後得到最小值。

public class stringcompare implements comparable

@override

public boolean compareto(stringcompare str)

return false;

}}

以上是非泛型類實現泛型介面,所以要填充型別,很多人可能會發現介面填充為什麼是stringcompare,這是由於stringcompare繫結了comparable介面,那麼填充的時候也要用stringsompare型別來填充,最後是呼叫函式:

stringcompare result = min(new  stringcompare("123"),new stringcompare("234"),new stringcompare("59897"));

log.d(tag,"min:"+result.mstr);

(2)繫結型別

假設我們有乙個水果攤,有許多水果,需要列印出填充進去的水果

class fruit 

public void setname(string name)

}

通過泛型函式來提取名字

public static string getfruitname(t t)
已知水果都會繼承fruit類

class banana extends fruit

} }

}

同過就可以限定填充進去必定是fruit的子類了。

最後呼叫

string name_1 = getfruitname(new banana());

log.d(tag,name_1);

log.d(tag,name_2);

也可以繫結多個限定

public static t foo(t a, u b)
什麼是萬用字元?首先還是引入型別point

class point

public point(t x,t y)

public void setx(t x)

public void sety(t y)

public t getx()

public t gety()

}

然後生成四個例項

pointintegerpoint = new point(3,3);

…………

pointfloatpoint = new point(4.3f,4.3f);

…………

pointdoublepoint = new point(4.3d,4.90d);

…………

pointlongpoint = new point(12l,23l);

…………

生成四個例項需要4個不同的變數,有沒有一種方法可以只生成乙個變數,然後將不同型別的例項賦值給它。

看下實現方式

point<?> point;

point = new point(3,3);

point = new point(4.3f,4.3f);

point = new point(4.3d,4.90d);

point = new point(12l,23l);

這裡的?就是無邊萬用字元。它代指任意符號,可代表任意的類。

無邊萬用字元只能用於填充泛型t,表示統配任何型別。不能用於定義變數。

box<?> box;

box = new box();

和泛型繫結類似,如果不加以限定,在後期的使用中編譯器可能不會報錯。所以我們同樣,要對?加以限定。

point<? extends number> point;
當將t填充為string和object時,賦值給point就會報錯!

這裡雖然是指派生自number的任意型別,但大家注意到了沒: new point();也是可以成功賦值的,這說明包括邊界自身。

再重複一遍:無邊界萬用字元只是泛型t的填充方式,給他加上限定,只是限定了賦值給它(比如這裡的point)的例項型別。

如果想從根本上解決亂填充point的問題,需要從point泛型類定義時加上:

class point
注意:

point<? extends number> point;

point = new point(3.33);

number number = point.getx();

point.setx(new integer(222));

第四行會報錯,為什麼呢?因為填充point的泛型變數t是<? extends number>,這是乙個未知型別,不能用來設定內部值。

但是取值的時候,由於泛型變數t被填充為<? extends number>,所以編譯器能確定t是number的子類,編譯器就回用number來填充。

<? extends number> 指的是被填充為number的子類,那麼<? super number> 就是指填充t為number的父類。

class ceo extends manager 

class manager extends employee

class employee

list<? super manager> list;

list = new arraylist();

//存list.add(new employee()); //編譯錯誤

list.add(new manager());

list.add(new ceo());

為啥新增employee例項時會報編譯錯誤呢?首先manager和ceo都為<? super manager>的子類,當他們被填充進去時就回被強制轉為manager的任意父類,而employee不一定是<? super manager>的子類, 所以不能會報錯。

總結 ? extends 和 the ? super 萬用字元的特徵,我們可以得出以下結論:

◆ 如果你想從乙個資料型別裡獲取資料,使用 ? extends 萬用字元(能取不能存)

◆ 如果你想把物件寫入乙個資料結構裡,使用 ? super 萬用字元(能存不能取)

◆ 如果你既想存,又想取,那就別用萬用字元。

java泛型介紹及使用

泛型 泛型是程式的一種特性。允許程式設計師在編寫 時定義一些可變的部分,那些部分在使用前必須做出指明。泛型是引用型別,是堆物件主要是引入了型別引數這個概念。可以直接理解 在定義型別不確定的型別叫泛型 泛型常規的用法 public classgeneral fanxing 不指定型別,可以不止乙個泛型...

泛型 二 泛型委託

using system using system.collections.generic using system.linq using system.text namespace 泛型委託 public event stackeventhandler,stackeventargs stackev...

泛型 定義和使用含有泛型的方法

定義和使用含有泛型的方法 泛型定義在方法的修飾符和返回值型別之間 格式 修飾符 返回值型別 方法名 引數列表 使用泛型 含有泛型的方法,在呼叫方法的時候確定泛型的資料型別 傳遞什麼型別的引數,泛型就是什麼型別 例如 public class genericmethod 定義乙個含有泛型的靜態方法 p...