首頁 Java java教程 Java中的泛型詳解

Java中的泛型詳解

Jan 18, 2017 am 10:54 AM

所謂泛型:就是允許在定義類別、介面指定類型形參,這個類型形參在將在宣告變數、建立物件時決定(即傳入實際的型別參數,也可稱為型別實參)

泛型類別或介面

「菱形」語法

//定义
 
public interface List<E> extends Collection<E>  
 
public class HashMap<K,V> extends AbstractMap<K,V>  implements Map<K,V>, Cloneable, Serializable 
//使用
 
List<String> list = new ArrayList();
 
//Java7以后可以省略后面尖括号的类型参数
 
List<String> list = new ArrayList<>();
登入後複製

從泛型類派生子類

//方式1
 
public class App extends GenericType<String>
 
//方式2
 
public class App<T> extends GenericType<T>
 
//方式3
 
public class App extends GenericType
登入後複製

偽泛型

不存在真正的泛型類,泛型類對Java虛擬機來說是透明的. JVM並不知道泛型類別的存在,換句話說,JVM處理泛型類別和普通類別沒什麼區別的.因此在靜態方法、靜態初始化區塊、靜態變數裡面不允許使用類型形參。
- 以下方式都是錯誤的

private static T data;
 
static{
 
    T f;
 
}
 
public static void func(){
 
    T name = 1;
 
}
登入後複製

下面的例子可以從側面驗證不存在泛型類

public static void main(String[] args){
 
        List<String> a1 = new ArrayList<>();
        List<Integer> a2 = new ArrayList<>();  
    System.out.println(a1.getClass() == a2.getClass());
 
    System.out.println(a1.getClass());
 
    System.out.println(a2.getClass());
 
}
登入後複製

輸出

true
 
class java.util.ArrayList
 
class java.util.ArrayList
登入後複製

類型通配符

首先必須明確,假如FooListBar是一點的父類,但< Foo>並不是List的父類別.為了表示各種泛型的父類別,Java使用"?"來表示泛型通配.即List來表示各種泛型List的父類別.帶這種通配符List泛型不能設定(set)元素,只能取得(get)元素。因為程式無法確定List中的類型,所以不能新增物件。但取得的物件肯定是Object類型。

以下方法會編譯出錯:

List<?> list = new ArrayList<>();
 
list.add(new Object());
登入後複製

主意幾點:

1.List物件不能被當成List物件使用,也就是說:List類別並不是List類別的子類別。

2.陣列和泛型有所不同:假設Foo是Bar的一個子型別(子類別或子介面),那麼Foo[]依然是Bar[]的子型別;但G不是G的子類型。

3.為了表示各種泛型List的父類,我們需要使用類型通配符,類型通配符是一個問號(?),將一個問號作為類型實參傳給List集合,寫作:List(意思是未知類型元素的List)。這個問號(?)被稱為通配符,它​​的元素類型可以匹配任何類型。

通配符的上限

List表示所有SuperType泛型List的父類或本身。有通配符上限的泛型不能有set方法,只能有get方法。

設定通配符上限能解決如下問題:Dog是Animal子類,有個getSize方法要獲取傳入List的個數,代碼如下

abstract class Animal {
    public abstract void run();
}
class Dog extends Animal {
    public void run() {
        System.out.println("Dog run");
    }
}
public class App {
    public static void getSize(List<Animal> list) {
        System.out.println(list.size());
    }
    public static void main(String[] args) {
        List<Dog> list = new ArrayList<>();
        getSize(list); // 这里编译报错
    }
}
登入後複製

這裡編程出錯的原因是List並不是List的父類。解一可以把getSize方法中形參List改為List,不過這樣的話在每次get物件的時候都要強制型別轉換,比較麻煩。使用通配符上限很好的解決了這個問題,可以把List改為List,編譯就不會錯了,也不用型別轉換。


通配符的下限

List表示SubType泛型List的下限。有通配符上限的泛型不能有get方法,只能有set方法。

泛型方法

如果定義類別、介面是沒有使用型別形參,但定義方法時想自己定義型別形參,這也是可以的,JDK1.5也提供了泛型方法的支援。泛型方法的方法簽名比普通方法的方法簽名多了類型形參聲明,類型形參聲明以尖括號括起來,多個類型形參之間以逗號(,)隔開,所有類型形參聲明放在方法修飾符與方法傳回值型別之間.語法格式如下:

修饰符 返回值类型 方法名(类形列表){
 
//方法体
 
}
登入後複製

泛型方法允許型別形參被用來表示方法的一個或多個參數之間的型別依賴關係,或是方法傳回值與參數之間的類型依賴關係。如果沒有這樣的類型依賴關係,就不應該使用泛型方法。 Collections的copy方法就使用泛型方法:

 public static <T> void copy(List<? super T> dest, List<? extends T> src){ ...}
登入後複製

這個方法要求src型別必須是dest型別的子類別或本身。

擦除和轉換

在嚴格的泛型程式碼裡,帶有泛型聲明的類別總是應該帶著型別參數。但為了與舊的Java程式碼保持一致,也允許在使用帶有泛型聲明的類別時不指定類型參數。如果沒有為這個泛型類別指定型別參數,則該型別參數被稱為一個raw type(原始型別),預設是該宣告該參數時指定的第一個上限型別。

當把一個具有泛型資訊的物件賦給另一個沒有泛型資訊的變數時,則所有在尖括號之間的類型資訊都被丟掉了。比如說一個List型別轉換為List,則該List對集合元素的型別檢查變成了成型變數的上限(即Object),這種情況被為擦除。

範例

class Apple<T extends Number>
 
{
 
 T size;
 
 public Apple()
 
 {
 
 }
 
 public Apple(T size)
 
 {
 
  this.size = size;
 
 }
 
 public void setSize(T size)
 
 {
 
  this.size = size;
 
 }
 
 public T getSize()
 
 {
 
  return this.size;
 
 }
 
}
 
public class ErasureTest
 
{
 
 public static void main(String[] args)
 
 {
 
  Apple<Integer> a = new Apple<>(6);    // ①
 
  // a的getSize方法返回Integer对象
 
  Integer as = a.getSize();
 
  // 把a对象赋给Apple变量,丢失尖括号里的类型信息
 
  Apple b = a;      // ②
 
  // b只知道size的类型是Number
 
  Number size1 = b.getSize();
 
  // 下面代码引起编译错误
 
  Integer size2 = b.getSize();  // ③
 
 }
 
}
登入後複製

更多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

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

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

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

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

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

如何將姓名轉換為數字以實現排序並保持群組中的一致性? 如何將姓名轉換為數字以實現排序並保持群組中的一致性? 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初學者會遇到將一個對象轉換成數組的�...

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

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

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

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

See all articles