不忘初心 砥礪前行, Tomorrow Is Another Day !
相關文章
引言
本文概要:
- 泛型的基本使用
- 泛型類
- 泛型介面
- 泛型函式
- 泛型的進階使用
- 型別繫結
- 萬用字元
泛型的基本使用
本節概要:
- 泛型類,介面,函式的定義
泛型的優點:
- 不用強制轉換
- 如果傳入型別不對,編譯時會報錯
一. 泛型類的定義
1.1 單泛型變數類的定義
public class Location<T>{//識別符號號可以隨意寫
private T x ;
private T y ;
public void setX(T x){//作為引數
this.x = x ;
}
public void setY(T y){
this.y = y ;
}
public T getX(){//作為返回值
return this.x ;
}
public T getY(){
return this.y ;
}
}
複製程式碼
1.2 多泛型變數類的定義
以 , 進行分隔
public class MoreLocation<T,U> {//識別符號號可以隨意寫
private T x;
private U y;
public void setX(T x) {//作為引數
this.x = x;
}
public void setY(U y) {
this.y = y;
}
public T getX() {//作為返回值
return this.x;
}
public U getY() {
return this.y;
}
}
複製程式碼
1.3 識別符號號的字母規範.
雖然識別符號號可以隨意取,但為了提高可讀性,一般遵循以下規則.
- E — Element,常用在java Collection裡,如:List,Iterator,Set
- K,V — Key,Value,代表Map的鍵值對
- N — Number,數字
- T — Type,型別,如String,Integer等等
二. 泛型介面的定義
在介面上定義泛型與在類中定義泛型是一樣的
interface ILocation<T>{ // 在介面上定義泛型
T getZ() ;
void setZ(T z);
}
複製程式碼
2.1 非泛型類實現泛型介面
public class LocationImpl implements ILocation<String>{
private String z ;
public LocationImpl(String z){
this.setZ(z) ;
}
@Override
public void setZ(String z){
this.z = z ;
}
@Override
public String getZ(){
return this.z ;
}
}
複製程式碼
2.2 泛型類實現泛型介面
publick class LocationImpl<T,K,U> implements ILocation<U>{ //把第三個泛型變數U用來填充介面
private U z ;
private T x;
private K y;
public LocationImpl(U z){
this.setZ(z) ;
}
@Override
public void setZ(U z){
this.z = z ;
}
@Override
public U getZ(){
return this.z ;
}
}
複製程式碼
三. 泛型函式的定義
在方法的返回值前加上來表示泛型變數.
public class MethodLocation {
public static <T> void staticMethod(T text) {
System.out.println("staticMethod:" + text);
}
//返回值與形參中存在泛型
public <T> T normalMethod(T text) {
System.out.println("normalMethod:" + text);
return text;
}
//定義泛型陣列, T[]相當於String[].
public static <T> T[] funArray(T...arg){ // 接收可變引數
return arg ; // 返回泛型陣列
}
public static void main(String[] args) {
MethodLocation methodLocation = new MethodLocation();
String text1 = methodLocation.normalMethod("hello");//方法1
String text2 = methodLocation.<String>normalMethod("genericity");//方法2
System.out.println("from main method:"+text1);
System.out.println("--------------------------");
Integer[] intArray = MethodLocation.funArray(1, 2, 3, 4, 5, 6);
System.out.println(Arrays.toString(intArray));
}
}
//輸出結果
normalMethod:hello
normalMethod:genericity
from main method:hello
--------------------------
[1, 2, 3, 4, 5, 6]
複製程式碼
注意:雖然方法2是推薦方式,但實際在IDEA中會提示使用方法1,這是因為它會實時檢測傳入型別是否一致,不一致直接提醒編譯不通過.
泛型的進階使用
本節概要:
- 型別繫結
- 萬用字元
一. 型別繫結
在前一節中,T只能是Object的子類,所以在編譯時只能呼叫Object類的相關方法.假如現在有個dog類,我們想在編譯時就呼叫他父類Animal的方法.這時就需要用到型別繫結.
定義:
< T extends BoundingType >
T和BoundingType可以是類,也可以是介面.
此處的==extends==僅僅表示子型別,不等同於繼承.
優點:
- 對泛型加以限定
- 泛型變數T,可以使用BoundingType內部的函式.
//省略....建立dog,Animal,IAction相關程式碼.
public class TypeBind {
public static void main(String[] args) {
Dog dog = new Dog("旺財");
String nameClass = getAnimalNameClass(dog);
System.out.println(nameClass);
System.out.println("---------------");
String actionInterface = getAnimalActionInterface(dog);
System.out.println(actionInterface);
System.out.println("---------------");
String nameAction = getAnimalNameAndAction(dog, dog);
System.out.println(nameAction);
}
//繫結類
private static <T extends Animal> String getAnimalNameClass(T sub) {
//這樣編譯時,就能呼叫Animal中的方法.
return sub.getName();
}
//繫結介面
private static <T extends IAction> String getAnimalActionInterface(T sub) {
return sub.howl();
}
//多個泛型繫結多個型別,通過&符號指定多個型別
private static <T extends Animal & Serializable, U extends IAction & Serializable> String
getAnimalNameAndAction(T sub1, U sub2) {
return sub1.getName() + sub2.howl();
}
}
複製程式碼
二. 萬用字元
萬用字元的意義就是它是一個未知的符號,可以是代表==任意的類==,通常用?號表示.
作用:用於填充泛型變數T,表示代表任意型別!僅僅是填充方式的一種.
//使用位置有且只有,只能用來在生成泛型例項時使用.
Location<?> location;
location = new Location<Integer>();
複製程式碼
2.1 萬用字元?的extends繫結
- 指填充為派生於XXX的任意子類的話.
- 所以例項能取不能存.
Location<? extends Number> location;
location = new Location<Integer>(2,3);
//取
Number number = location.getX();//編譯通過
//存
location.setX(new Integer(123);//編譯報錯
複製程式碼
location的型別由<? extends Number>決定,並不會因為location = new Location(2,3)而改變型別.所以不能確定萬用字元型別.
2.2 萬用字元?的super繫結
- 則表示填充為任意XXX的父類.
- 例項能存不能取.
/**
* 準備三個類Animal(動物),Mammal(哺乳動物),Mouse(老鼠).
* Mouse 繼承 Mammal, Mammal 繼承 Animal.
* .....省略相關類程式碼
*/
List<? super Mammal> list;
list = new ArrayList<Animal>;
//取
Animal animal = list.get(0);//編譯報錯
Object object = list.get(0);
//存
list.add(new Animal());//編譯報錯
list.add(new Mammal());
list.add(new Mouse());
複製程式碼
取的時候報錯,編譯器不能確定<? super Mammal>的父類就是Animal.
至於存的時候報錯,同樣因為是未知型別,編譯器只能確定萬用字元型別為Mammal及其子類.
對於編譯器,只要能確定萬用字元型別,就會編譯通過.否則會報錯.
最後的話:
本文只是對參考連結的內容總結,如需詳細瞭解,請參考啟艦大佬的部落格連結.
由於本人技術有限,如有錯誤的地方,麻煩大家給我提出來,本人不勝感激,大家一起學習進步.
參考連結: