1. 程式人生 > 其它 >java 泛型中的上界(extend)和下界(super)

java 泛型中的上界(extend)和下界(super)

1、匹配任意型別的萬用字元
在開發中物件的引用傳遞(向上向下傳遞)是最常見的,但是,在泛型的操作中,在進行引用傳遞的時候泛型型別必須匹配才可以傳遞,否則不能傳遞。
例如,如下沒有進行泛型型別匹配,一個是String,一個是Object型別。

package Thread1;
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 demo1{ public static void main(String args[]){ Info<String> i = new Info<String>() ; // 使用String為泛型型別 i.setVar("MLDN") ; // 設定內容 fun(i) ;                    //
把String泛型型別的i物件傳遞給Object泛型型別的temp。 } public static void fun(Info<Object> temp){ // 接收Object泛型型別的Info物件 System.out.println("內容:" + temp) ; } };

編譯發生錯誤。

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    The method fun(Info<Object>) in the type demo1 is not applicable for
the arguments (Info<String>) at Thread1.demo1.main(demo1.java:18)

泛型物件進行引用傳遞的時候,型別必須一致,如果非要傳遞,則可以將fun方法中Info引數的泛型取消掉(變成 void fun(Info temp))。、
以上確實改進了功能,但是似乎不是很妥當,畢竟之前指定過泛型。
以上程式在fun()方法中使用"Info<?>"的程式碼形式,表示可以使用任意的泛型型別物件,這樣的話fun()方法定義就合理了,但是使用以上方法也有需要注意的地方,
即:如果使用“?“接收泛型物件的時候,則不能設定被泛型指定的內容。

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 GenericsDemo14{
    public static void main(String args[]){
        Info<String> i = new Info<String>() ;        // 使用String為泛型型別
        i.setVar("MLDN") ;                            // 設定內容
        fun(i) ;
    }
    public static void fun(Info<?> temp){        // 可以接收任意的泛型物件
        System.out.println("內容:" + temp) ;
    }
};

如果使用”?“意味著可以接收任意的內容,但是此內容無法直接使得用”?“修飾的泛型的物件進行修改。如下就會出問題:

package Thread1;
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 demo1{
    public static void main(String args[]){
        Info<?> i = new Info<String>() ;        // 使用String為泛型型別
        i.setVar("MLDN") ;                            // 設定內容,這裡會出錯,因為”?“萬用字元修飾的物件只能接收,不能修改,也就是不能設定。
    }
};

執行結果:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    The method setVar(capture#1-of ?) in the type Info<capture#1-of ?> is not applicable for the arguments (String)

    at Thread1.demo1.main(demo1.java:17)

在使用”?“只能接收,不能修改。
2、受限泛型
之前設定泛型的時候,實際上是可以任意設定的,只要是類就可以設定。但是在JAVA的泛型中可以指定一個泛型的上限和下限。

設定上限

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 GenericsDemo17{
    public static void main(String args[]){
        Info<Integer> i1 = new Info<Integer>() ;        // 宣告Integer的泛型物件
        Info<Float> i2 = new Info<Float>() ;            // 宣告Float的泛型物件
        i1.setVar(30) ;                                    // 設定整數,自動裝箱
        i2.setVar(30.1f) ;                                // 設定小數,自動裝箱
        fun(i1) ;
        fun(i2) ;
    }
    public static void fun(Info<? extends Number> temp){    // 只能接收Number及其Number的子類
        System.out.print(temp + "、") ;
    }
};

執行成功。但是,如果傳人的泛型型別為String的話就不行,因為String不是Number子類。
在類中使用泛型上限。

package Thread1;
class Info<T extends Number>{    // 此處泛型只能是數字型別
    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 demo1{
    public static void main(String args[]){
        Info<Integer> i1 = new Info<Integer>() ;        // 宣告Integer的泛型物件
    }
};

如果在使用Info的時候設定成String型別,則編譯的時候將會出現錯誤(String不是Number子類):
設定下限

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 GenericsDemo21{
    public static void main(String args[]){
        Info<String> i1 = new Info<String>() ;        // 宣告String的泛型物件
        Info<Object> i2 = new Info<Object>() ;        // 宣告Object的泛型物件
        i1.setVar("hello") ;
        i2.setVar(new Object()) ;
        fun(i1) ;
        fun(i2) ;
    }
    public static void fun(Info<? super String> temp){    // 只能接收String或Object型別的泛型,String類的父類只有Object類
        System.out.print(temp + "、") ;
    }
};

Object類和String類都是String的父類,所有執行成功,但是如果此時用Integer則會出錯,因為integer並不是String父類。
3、解釋:泛型與子類繼承的限制。
一個類的子類可以通過物件多型性,為其父類例項化,但是在泛型操作中,子類的泛型型別是無法使用父類的泛型型別接收的。例如:Info<String>不能使用Info<Object>接收。
例如,以下肯定出錯。

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 GenericsDemo23{
    public static void main(String args[]){
        Info<String> i1 = new Info<String>() ;        // 泛型型別為String
        Info<Object> i2 = null ;
        i2 = i1 ;                  //這裡因為物件泛型型別不同,而出錯。
    }
};

總結:關於上界下界
上界的list只能get,不能add(確切地說不能add出除null之外的物件,包括Object)
下界的list只能add,不能get
add和get涉及到具體的資料型別了:
add方法是先給預新增的物件建立一個引用,再讓這個引用指向具體的父類或子類物件;
get方法是返回具體的類(假設為型別1),必須有一個型別1或型別1的父類引用去指向它;
規定了上界:如果add新增物件,java不知道要為哪一個具體的類新增引用,但java不會自動選擇;如果get物件,卻可以(人為地)使用上界類建立引用了(因為程式碼中規定了上界,一看便知)。
規定了下界:如果add新增物件,java不知道要為哪一個具體的類新增引用,這裡就可以(人為地)新增下界類的子類物件了(因為程式碼中規定了下界,一看便知);如果get物件,只能用預獲取的類的‘同類’或父類建立引用,但程式設計師不知道get出來的是哪個類。

郭慕榮部落格園