首頁 Java java教程 Java中泛型通配符和有界的型別參數

Java中泛型通配符和有界的型別參數

Aug 06, 2018 pm 04:55 PM

型別通配符

型別通配符一般是使用?來取代具體的型別實參(這裡是型別實參,而不是型別字參)。當操作類型時不需要使用類型的特定功能時,只使用Object類別中的功能,那麼可以用 ? 通配符來表未知類型。例如 List 在邏輯上是List、List 等所有List<具體類型實參>的父類別。

public class GenericTest {    
    public static void main(String[] args) {
        List<String> name = new ArrayList<String>();
        List<Integer> age = new ArrayList<Integer>();
        List<Number> number = new ArrayList<Number>();   
        name.add("zwj");
        age.add(18);
        number.add(120);
   
        getNumberData(age); // 报错
        getNumberData(number); // 120
        getData(name);  // zwj
        getData(age); // 18
        getData(number); // 120
        //getUperNumber(name); // 出现错误,方法中的参数已经限定了参数泛型上限为Number
        getUperNumber(age); //18
        getUperNumber(number); //120       
    }
    /**
     * 在使用List<Number>作为形参的方法中,不能使用List<Ingeter>的实例传入,
     * 也就是说不能把List<Integer>看作为List<Number>的子类;
     */
    public static void getNumberData(List<Number> data) {
        System.out.println("data :" + data.get(0));
    }
    /**
     * 使用类型通配符可以表示同时是List<Integer>和List<Number>的引用类型。
     * 类型通配符一般是使用?代替具体的类型实参,注意此处是类型实参;
     * 和Number、String、Integer一样都是一种实际的类型,可以把?看成所有类型的父类。
     */
    public static void getData(List<?> data) {
        System.out.println("data :" + data.get(0));
    }
    /**
     * 类型通配符上限通过形如List来定义,如此定义就是通配符泛型值接受Number及其下层子类类型。
     */
    public static void getUperNumber(List<? extends Number> data) {
          System.out.println("data :" + data.get(0));
    }
}
登入後複製

 有界的型別參數

有的時候我們會想要限制那些被允許傳遞到一個型別參數的型別範圍。例如,一個操作數字的方法可能只希望接受Number或Number子類別的實例。這時猴就需要為泛型添加上邊界,即傳入的類型實參必須是指定類型的子類型。

要宣告一個有界的型別參數,先列出型別參數的名稱,接著是extends或super關鍵字,最後再跟著它的上界或下界。由此可以知道泛型的上下邊界的添加必須與泛型的聲明在一起 。

表示該通配符所代表的型別是T型別的子類別。例如往集合中新增元素時,既可以新增E型別對象,又可以加入E的子類型對象。為什麼?因為取的時候,E型別既可以接收E類對象,又可以接收E的子類型對象。

表示該通配符所代表的類型是T類型的父類別。例如從集合中取得元素進行操作的時候,可以用目前元素的型別接收,也可以用目前元素的父型別接收。

public class GenericMethodTest {
    // 比较三个值并返回最大值
    public static <T extends Comparable<T>> T getMaxNuum(T x, T y, T z) {                     
        T max = x; // 假设x是初始最大值
        if ( y.compareTo( max ) > 0 ){
            max = y; //y 更大
        }
        if ( z.compareTo( max ) > 0 ){
            max = z; // 现在 z 更大           
        }
        return max; // 返回最大对象
    }
    public static void main( String args[] ) {
        System.out.println( "结果 " + getMaxNuum(3, 4, 5) );  // 结果 5
        System.out.println( "结果 " + getMaxNuum(1.2, 6.6, 10.10) ); // 结果 10.10
   }
}
登入後複製

我們也可以把先前的泛型類別的定義改一下:

public class GenericClassDemo<T extends Number> { 
    private T t;   
    public GenericClassDemo() { 
    }
    public GenericClassDemo(T t) { 
        this.t = t;
    }
    public void setT(T t) {
        this.t = t;
    }
    public T getT(){ 
        return t;
    }
}
登入後複製

此時在實例化GenericClassDemo泛型類別時參數型別只能是Number和Number的子類別。在此基礎上我們再來看一個泛型方法的範例:

/**
 * 在泛型方法中添加上下边界限制的时候, 必须在泛型声明的时候添加;
 * 也就是在权限修饰符与返回值之间的<T>上添加上下边界
 */
public <T extends Number> T getT(GeneriClassDemo<T> demo){
    T t = demo.getT();
    return t;
}
登入後複製

 泛型數組

在java中是不能建立一個確切的泛型類型的陣列的。

List<String>[] lsa = new ArrayList<String>[10];  // Not really allowed. 
Object o = lsa;    
Object[] oa = (Object[]) o;    
List<Integer> li = new ArrayList<Integer>();    
li.add(new Integer(3));    
oa[1] = li; // Unsound, but passes run time store check    
String s = lsa[1].get(0); // Run-time error: ClassCastException.
登入後複製

這種情況下,由於JVM泛型的擦除機制,在運行時JVM是不知道泛型資訊的,所以可以給oa[1]賦上一個ArrayList而不會出現異常,但在取出資料的時候卻要做一次型別轉換,所以就會出現ClassCastException,如果可以進行泛型陣列的聲明,上面說的這種情況在編譯期將不會出現任何的警告和錯誤,只有在執行時才會出錯。而對泛型數組的聲明進行限制,對於這樣的情況,可以在編譯期提示程式碼有型別安全問題,比沒有任何提示要強很多。

下面採用通配符的方式是被允許的:數組的型別不可以是型別變量,除非是採用通配符的方式,因為對於通配符的方式,最後取出資料是要做顯式的類型轉換的。

List<?>[] lsa = new List<?>[10]; // OK, array of unbounded wildcard type.    
Object o = lsa;    
Object[] oa = (Object[]) o;    
List<Integer> li = new ArrayList<Integer>();    
li.add(new Integer(3));    
oa[1] = li; // Correct.    
Integer i = (Integer) lsa[1].get(0); // OK
登入後複製

相關文章:

java 泛型中 T 和 問號(通配符)的差異

Java中的泛型詳解

#

以上是Java中泛型通配符和有界的型別參數的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

公司安全軟件導致應用無法運行?如何排查和解決? 公司安全軟件導致應用無法運行?如何排查和解決? Apr 19, 2025 pm 04:51 PM

公司安全軟件導致部分應用無法正常運行的排查與解決方法許多公司為了保障內部網絡安全,會部署安全軟件。 ...

如何使用MapStruct簡化系統對接中的字段映射問題? 如何使用MapStruct簡化系統對接中的字段映射問題? Apr 19, 2025 pm 06:21 PM

系統對接中的字段映射處理在進行系統對接時,常常會遇到一個棘手的問題:如何將A系統的接口字段有效地映�...

如何優雅地獲取實體類變量名構建數據庫查詢條件? 如何優雅地獲取實體類變量名構建數據庫查詢條件? Apr 19, 2025 pm 11:42 PM

在使用MyBatis-Plus或其他ORM框架進行數據庫操作時,經常需要根據實體類的屬性名構造查詢條件。如果每次都手動...

如何將姓名轉換為數字以實現排序並保持群組中的一致性? 如何將姓名轉換為數字以實現排序並保持群組中的一致性? Apr 19, 2025 pm 11:30 PM

將姓名轉換為數字以實現排序的解決方案在許多應用場景中,用戶可能需要在群組中進行排序,尤其是在一個用...

IntelliJ IDEA是如何在不輸出日誌的情況下識別Spring Boot項目的端口號的? IntelliJ IDEA是如何在不輸出日誌的情況下識別Spring Boot項目的端口號的? Apr 19, 2025 pm 11:45 PM

在使用IntelliJIDEAUltimate版本啟動Spring...

Java對像如何安全地轉換為數組? Java對像如何安全地轉換為數組? Apr 19, 2025 pm 11:33 PM

Java對象與數組的轉換:深入探討強制類型轉換的風險與正確方法很多Java初學者會遇到將一個對象轉換成數組的�...

使用TKMyBatis進行數據庫查詢時,如何優雅地獲取實體類變量名構建查詢條件? 使用TKMyBatis進行數據庫查詢時,如何優雅地獲取實體類變量名構建查詢條件? Apr 19, 2025 pm 09:51 PM

在使用TKMyBatis進行數據庫查詢時,如何優雅地獲取實體類變量名以構建查詢條件,是一個常見的難題。本文將針...

電商平台SKU和SPU數據庫設計:如何兼顧用戶自定義屬性和無屬性商品? 電商平台SKU和SPU數據庫設計:如何兼顧用戶自定義屬性和無屬性商品? Apr 19, 2025 pm 11:27 PM

電商平台SKU和SPU表設計詳解本文將探討電商平台中SKU和SPU的數據庫設計問題,特別是如何處理用戶自定義銷售屬...

See all articles