天天看點

一. 重識Java之夯實泛型引言

不忘初心 砥砺前行, Tomorrow Is Another Day !

相關文章

  • 一. 重識Java之夯實泛型
  • 二. 重識Java之夯實注解
  • 三. 重識Java之夯實反射

引言

本文概要:

  1. 泛型的基本使用
    • 泛型類
    • 泛型接口
    • 泛型函數
  2. 泛型的進階使用
    • 類型綁定
    • 通配符

泛型的基本使用

本節概要:

  • 泛型類,接口,函數的定義

泛型的優點:

  1. 不用強制轉換
  2. 如果傳入類型不對,編譯時會報錯

一. 泛型類的定義

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,這是因為它會實時檢測傳入類型是否一緻,不一緻直接提醒編譯不通過.

泛型的進階使用

本節概要:

  1. 類型綁定
  2. 通配符

一. 類型綁定

在前一節中,T隻能是Object的子類,是以在編譯時隻能調用Object類的相關方法.假如現在有個dog類,我們想在編譯時就調用他父類Animal的方法.這時就需要用到類型綁定.

定義:

< T extends BoundingType >

T和BoundingType可以是類,也可以是接口.

此處的==extends==僅僅表示子類型,不等同于繼承.

優點:

  1. 對泛型加以限定
  2. 泛型變量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及其子類.

對于編譯器,隻要能确定通配符類型,就會編譯通過.否則會報錯.

最後的話:

本文隻是對參考連結的内容總結,如需詳細了解,請參考啟艦大佬的部落格連結.

由于本人技術有限,如有錯誤的地方,麻煩大家給我提出來,本人不勝感激,大家一起學習進步.

參考連結:

  • blog.csdn.net/harvic88092…
  • blog.csdn.net/harvic88092…