JAVA泛型詳解 --- 學習筆記

原文請戳此處!!!


1. 普通泛型

class Point<T>{                  //此處可以隨便寫標識符號,T只是Type的簡稱
    private T var;               // var的類型由T指定,也就是:由外部指定
    public T getVar(){           //返回值得類型也是由外部決定的
        return var;
    }
    public void setVar(T var){    //設置的類型也由外部決定
        this.var = var;
    }
}
public class GenericsDemo01{
    public static void main(String args[]){
        Point<String> p = new Point<String>();   //此處決定了類Point<T>裏面的var類型爲String類型
        p.setVar("forfan06");      //設置字符串
        System.out.println(p.getVar().length());  //此處分兩步,一是取得字符串;二是獲得字符串長度
    }
}

-----------------------------------------------------------------------------------------------------------

class Notepad<K, V>{    //指定了兩個泛型類型T和V,當然,此處的T和V可以換成其他字符。但是爲了方便識別,一般取一個有意義單詞的大寫首字母
    private K key;      // 此處的T和V均是由外部決定的
    private V value;
    public K getKey(){
        return this.key;
    }
    public V getValue(){
        return this.value;
    }
    public void setKey(K key){
        this.key = key;
    }
    public void setValue(V value){
        this.value = value;
    }
}
public class GenericsDemo02{
    public static void main(String args[]){
        Notepad<String, Integer> t = null;        //定義了兩個泛型類型的對象。
        t = new Notepad<String, Integer>();       //裏面的key和value分別爲String和Integer類型。
        t.setKey("飯飯");                          //設置對象t的內容
        t.setValue(20);
        
        System.out.print("姓名:" + t.getKey());      //獲取對象t的屬性
        System.out.println(", 年齡:" + t.getValue());
    }
}

2. 通配符

class Info<T>{
    private T var;     //定義泛型變量,由外部決定
    public void setVar(T var){
        this.var = var;
    }
    public T getVar(){
        return this.var;
    }
    public String toString(){   //直接打印
        return this.var.toString();
    }
}
public class GenericsDemo03{
    public static void main(String args[]){
        Info<String> i = new Info<String>();  //使用String類型爲泛型類型
        i.setVar("forfan06");
        fun(i);
    }
    public static void fun(Info<?> info){    //此處Info<?>裏面沒有明確指明泛型類型,說明可以接受任意的泛型對象。
        System.out.println("內容是:" + info);
    }
}

更好的驗證通配符的作用:增加Info<Integer>如下代碼:也可以正常運行!!!

class Info<T>{
    private T var;     //定義泛型變量,由外部決定
    public void setVar(T var){
        this.var = var;
    }
    public T getVar(){
        return this.var;
    }
    public String toString(){   //直接打印
        return this.var.toString();
    }
}
public class GenericsDemo03{
    public static void main(String args[]){
        Info<String> i = new Info<String>();  //使用String類型爲泛型類型
        i.setVar("forfan06");
        fun(i);
        Info<Integer> s = new Info<Integer>();
        s.setVar(28);
        fun(s);
    }
    public static void fun(Info<?> info){    //此處Info<?>裏面沒有明確指明泛型類型,說明可以接受任意的泛型對象。
        System.out.println("內容是:" + info);
    }
}

上面程序若修改爲:

class Info<T>{
    private T var;     //定義泛型變量,由外部決定
    public void setVar(T var){
        this.var = var;
    }
    public T getVar(){
        return this.var;
    }
    public String toString(){   //直接打印
        return this.var.toString();
    }
}
public class GenericsDemo03{
    public static void main(String args[]){
        Info<String> i = new Info<String>();  //使用String類型爲泛型類型
        i.setVar("forfan06");
        fun(i);
        Info<Integer> s = new Info<Integer>();
        s.setVar(28);
        fun(s);
    }
    public static void fun(Info<T> info){    //此處Info<?>裏面沒有明確指明泛型類型,說明可以接受任意的泛型對象。
        System.out.println("內容是:" + info);
    }
}

則會出現編譯錯誤!!!!!!!!!!!!

GenericsDemo03.java:22: error: cannot find symbol
    public static void fun(Info info){    
                                ^
  symbol:   class T
  location: class GenericsDemo03
1 error

編譯錯誤


3. 受限泛型

上限:

class Info<T>{
    private T var;
    public void setVar(T var){
        this.var = var;
    }
    public T getVar(){
        return this.var;
    }
    public String toString(){
        return this.var.toString();
    }
}
public class GenericsDemo04{
    public static void main(String args[]){
        Info<Integer> i1 = new Info<Integer>();          //聲明Integer類的泛型對象
        Info<Float> i2 = new Info<Float>();              //聲明Float類的泛型對象
        i1.setVar(27);                                   //設置整數(小數), 自動裝箱!!
        i2.setVar(10.53f);
        fun(i1);
        fun(i2);
    }
    public static void fun(Info<? extends Number> temp){   //只能接受Number類及其子類的實例!!!!
        System.out.print(temp + "、");
    }
}

下限:

class Info<T>{
    private T var;
    public void setVar(T var){
        this.var = var;
    }
    public T getVar(){
        return this.var;
    }
    public String toString(){
        return this.var.toString();
    }
}
public class GenericsDemo04{
    public static void main(String args[]){
        Info<String> i1 = new Info<String>();
        Info<Object> i2 = new Info<Object>();
        i1.setVar("forfan06");
        i2.setVar(new Object());
        
        fun(i1);
        fun(i2);
    }
    public static void fun(Info<? super String> temp){     //只能接收String類或其父類(Object類)類型的泛型
        System.out.print(temp + "、");
    }
}


4. 泛型無法向上轉型

class Info<T>{
    private T var;
    public void setVar(T var){
        this.var = var;
    }
    public T getVar(){
        return this.var;
    }
    public String toString(){
        return this.var.toString();
    }
}
public class GenericsDemo05{
    public static void main(String args[]){
        Info<String> i1 = new Info<String>();
        Info<Object> i2 = null;
        i2 = i1;   //此句會出錯:error: incompatible types
    }
}

運行得到錯誤:

GenericsDemo05.java:17: error: incompatible types
        i2 = i1;   //此句會出錯:incompatible types
             ^
  required: Info
  found:    Info
1 error

編譯錯誤
  • 此時Info<String> i1, Info<Object> i2中,i2已經不是i1的基類了!!!所以不存在向上轉型這一說法!!!!!

5. 泛型接口

interface Info<T>{          //在接口中定義泛型
    public T getVar();      //定義抽象方法,抽象方法的返回值就是泛型類型
}
class InfoImpl<T> implements Info<T>{   //定義泛型接口的子類
    private T var;
    public InfoImpl(T var){             //通過構造方法設置屬性內容
        this.var = var;
    }
    public T getVar(){
        return this.var;
    }
    public void setVar(T var){
        this.var = var;
    }
}
public class GenericsDemo06{
    public static void main(String args[]){
        Info<String> i = null;         //聲明接口對象,泛型T此時爲String類型
        i = new InfoImpl<String>("forfan06");     //通過子類實例化對象
        System.out.println("內容:" + i.getVar());
    }
}

interface Info<T>{          //在接口中定義泛型
    public T getVar();      //定義抽象方法,抽象方法的返回值就是泛型類型
}
class InfoImpl implements Info<String>{   //定義泛型接口的子類
    private String var;
    public InfoImpl(String var){             //通過構造方法設置屬性內容
        this.var = var;
    }
    public String getVar(){
        return this.var;
    }
    public void setVar(String var){
        this.var = var;
    }
}
public class GenericsDemo06{
    public static void main(String args[]){
        Info i = null;   //聲明接口對象
        i = new InfoImpl("forfan06");  //通過子類實例化對象
        System.out.println("內容:" + i.getVar());
    }
}

6. 泛型方法

聲明格式:

[訪問權限] <泛型標識>  泛型標識 方法名稱([泛型標識 參數名稱])

class Demo{
    public <T> T fun(T t){       //可以接收任意類型的數據
        return t;                //直接把參數返回
    }
}
public class GenericsDemo07{
    public static void main(String args[]){
        Demo d= new Demo();
        String str = d.fun("forfan06");
        int i = d.fun(28);    //傳遞數字,自動裝箱
        System.out.println(str);
        System.out.println(i);
    }
}

7. 通過泛型方法返回泛型類型實例

class Info<T extends Number>{    //指定上限,只能是數字類型。(只能是Number類的子類)
    private T var;
    public T getVar(){
        return this.var;
    }
    public void setVar(T var){
        this.var = var;
    }
    public String toString(){   //覆寫Object類中的toString()方法
        return this.var.toString();
    }
}
public class GenericsDemo08{
    public static void main(String args[]){
        Info<Integer> i = fun(30);
        System.out.println(i.getVar());
    }
    public static <T extends Number> Info<T> fun(T param){      //方法中傳入或返回的泛型類型由調用方法時所設置的參數類型決定
        Info<T> temp = new Info<T>();    //根據傳入的數據類型實例化Info
        temp.setVar(param);              //將傳遞的內容設置到Info對象的var屬性中
        return temp;       //返回實例化對象
    }
}

8. 使用泛型統一傳入的參數類型

class Info<T>{
    private T var;
    public T getVar(){
        return this.var;
    }
    public void setVar(T var){
        this.var = var;
    }
    public String toString(){
        return this.var.toString();
    }
}
public class GenericsDemo09{
    public static void main(String args[]){
        Info<String> i1 = new Info<String>();
        Info<String> i2 = new Info<String>();
        i1.setVar("forfan06");
        i2.setVar("你好!");
        add(i1,i2);
    }
    public static <T> void add(Info<T> i1, Info<T> i2){
        System.out.println(i1.getVar() + " " + i2.getVar());
    }
}

9. 泛型數組

public class GenericsDemo10{
    public static void main(String args[]){
        Integer i[] = fun1(1, 2, 3, 4, 5, 6);  //返回泛型數組
        fun2(i);
    }
    public static <T> T[] fun1(T...arg){   //接收可變參數
        return arg;                        //返回泛型數組 
    }
    public static <T> void fun2(T param[]){    //輸出
        System.out.println("接收泛型數組:");
        for(T t:param){
            System.out.print(t + "、");
        }
    }
}

此時運行會得到以下警告:

GenericsDemo10.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

出現上面警告是因爲用到了JAVA5.0的泛型,而5.0的泛型不做類型檢查,例如ArrayList = a new ArrayList(); a.add("hello");這樣會出現警告!解決方法有以下幾種:

  1. 在方法的前面加上@SuppressWarnings("unchecked")
  2. 聲明泛型類型,例如ArrayList<Object> a = new ArrayList<Object>();
  3. 使用1.4兼容JDK來編譯, javac -source 1.4 Test.java
  4. 也可以查看警告信息,javac Xlint:unchecked Test.java。這樣會顯示詳細的警告信息。

10. 泛型的嵌套設置

class Info<T, V>{
    private T var;
    private V value;
    public Info(T var, V value){
        this.setVar(var);
        this.setValue(value);
    }
    public void setVar(T var){
        this.var = var;
    }
    public void setValue(V value){
        this.value = value;
    }
    public T getVar(){
        return this.var;
    }
    public V getValue(){
        return this.value;
    }
}
class Demo<S>{
    private S info;
    public Demo(S info){
        this.setInfo(info);
    }
    public void setInfo(S info){
        this.info = info;
    }
    public S getInfo(){
        return this.info;
    }
}
public class GenericsDemo11{
    public static void main(String args[]){
        Demo<Info<String, Integer>> d = null;      //將Info作爲Demo的泛型類型
        Info<String, Integer> i = null;            //Info指定兩個泛型類型
        i = new Info<String, Integer>("forfan06", 30);    //實例化Info對象
        d = new Demo<Info<String, Integer>>(i);           //在Demo類中設置Info類的對象
        System.out.println("內容一:" + d.getInfo().getVar());
        System.out.println("內容二:" + d.getInfo().getValue());
    }
}

泛型方法不一定要通過參數來確定泛型準確類型,可以只通過返回值,比如:

public static <E> ArrayList<E> new ArrayList(){
     return new ArrayList<E>();
}

public List<PrepaidHistory> queryHistories(Long skyid, PrepaidHistoryType type, Date from, Date end){
     ...
     return Lists.newArrayList();
}

這樣Lists.newArrayList();

智能的知道返回類型爲PrepaidHistory


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章