Java class 與泛型

泛化的 Class 引用

我們由一段代碼來切入今天的主題:

public class Demo {
    
    public static void main(String[] args) {
        try{
            Class<? extends Number> numClass = int.class;
            numClass = double.class;
            numClass = Integer.class;
        } catch(Exception e){
            e.printStackTrace();
        }
    }

}

上述代碼沒有任何的實際意義,但是能引出以下兩個問題:
1)Class 是什么類?
2)泛型有什么作用?
對于這兩個問題,我們的解答是:

  1. Class 的功能與使用

    • Class 類:Class 引用總是指向某個類的 Class 對象。Class 類可以用于制造類的實例,并包含可作用于這些實例的所有方法代碼,并且包含該類的靜態(tài)成員。
    • Class<?>Class 是等效的,但是使用 Class<?> 的好處是表示你并不是由于疏忽而未指定具體的類引用,而是選擇了非具體的版本。
  2. 使用帶泛型的 Class 引用的好處:

    • 使用 Class<?> 調(diào)用 getInstanse() 方法獲取到的對象是 Object 類型的實例。但如果使用 Class<Integer> 則是 Integer 類型的。

所以 Class 類包含了其他類的類型信息??捎糜谥圃祛惖膶嵗筒榭搭惖某蓡T和方法。

泛型通配符 extends 和 super

  • 為了引入通配符?
    Java 中 Integer 類繼承于 Number 類,但 Integer.class 并不是 Number.class 的子類 (objc比這優(yōu)雅多了),所以 Class<Number> numClass = Integer.class; 是不合法的。

extends 上界通配符

因為以上尷尬的情況,所以引入了 ? extends 通配符聲明 這個class 引用是用來引用繼承于 Number 的子類 class 對象。所以才能將 Integer.class 賦值給它。
我們以下圖為例子:

image.png

<? extends Fruit> 該類的set()方法失效。但取東西get()方法還有效。

Plate < ? extends Fruit > p = new Plate < Apple > (new Apple()); //不能存入任何元素
p.set(new Fruit());    //Error
p.set(new Apple());    //Error

super 下界通配符

聲明了? super Frult的泛型對象,能存放當(dāng)前類型和它所有父類的對象。

image.png

extends 相反,super 通配符會使get()方法失效,但是set()方法仍讓有效。

cast 方法

使用 cast() 可以對無法強制轉(zhuǎn)換的實例進行轉(zhuǎn)換。

public class Demo {
    
    public static void main(String[] args) {
        try{
            Number a = 1;
            Class<Integer> numClass = Integer.class;
            Integer i = numClass.cast(a);
            System.out.println(i);
        } catch(Exception e){
            e.printStackTrace();
        }
    }
}

泛型擦除

  • 我們在使用泛型的過程中,常常因為無法獲取泛型 T 的 class 引用。
    是因為編譯期在擦除后無法得知對象 T 的類型,但編譯器還是能保證最為返回值時仍然具有 T 類型。因為擦除在運行的邊界(進入和離開的地方),編譯器執(zhí)行了類型檢查并插入了轉(zhuǎn)型代碼。
public class Demo<T> {
    private T obj;
    public void set(T obj){
        this.obj = obj;
    }  
    public T get(){
        return this.obj;
    }
    public static void main(String[] args) {
        Demo<String> demo = new Demo<String>();
        demo.set("123");
        String str = demo.get(); // 等效于 (String) demo.get(),獲取到 Object 類型后強轉(zhuǎn)為 String 類型
        System.out.println(str);
    }
}

    Code:
       0: new           #3                  // class Demo
       3: dup
       4: invokespecial #4                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: ldc           #5                  // String 123
      11: invokevirtual #6                  // Method set:(Ljava/lang/Object;)V
      14: aload_1
      15: o #7                  // Method get:()Ljava/lang/Object;
      18: checkcast     #8                  // class java/lang/String
      21: astore_2
      22: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
      25: aload_2
      26: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      29: return
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 開發(fā)人員在使用泛型的時候,很容易根據(jù)自己的直覺而犯一些錯誤。比如一個方法如果接收List作為形式參數(shù),那么如果嘗試...
    時待吾閱讀 1,127評論 0 3
  • 本文大量參考Thinking in java(解析,填充)。 定義:多態(tài)算是一種泛化機制,解決了一部分可以應(yīng)用于多...
    谷歌清潔工閱讀 522評論 0 2
  • 我們知道,使用變量之前要定義,定義一個變量時必須要指明它的數(shù)據(jù)類型,什么樣的數(shù)據(jù)類型賦給什么樣的值。 假如我們現(xiàn)在...
    今晚打肉山閱讀 1,213評論 0 1
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,568評論 19 139
  • 我的夢我的夢,何處尋覓影蹤 我的夢我的夢一步一步丈量的彩虹
    在路上走著看天空閱讀 198評論 0 0

友情鏈接更多精彩內(nèi)容