java泛型設計---學習筆記

重點理解:泛型類可以看作普通類的工廠;泛型方法;類型變量的限定;類型擦除;

有關泛型轉換的事實:虛擬機中沒有泛型,只有普通的類和方法; 所有的類型參數都用它們的限定類型轉換; 橋方法被合成來保持多態; 爲保持類型安全性,必要時插入強制類型轉換。

泛型程序設計需要重點理解的內容:

聲明:代碼借用的“莫等閒”的,博客地址:https://blog.csdn.net/sunxianghuang/article/details/51982979。尊重原創和著作權。

泛型類型:用於通用型程序的設計。

    //泛型類型  
    class Pair<T> {    
        private T value;    
        public T getValue() {    
            return value;    
        }    
        public void setValue(T  value) {    
            this.value = value;    
        }      
    }  

原始類型:Object型是所有類型的超類,本是同根生的好處,其它的所有類型都可以向上轉型爲原始類。

//原始類型  
class Pair {    
    private Object value;    
    public Object getValue() {    
        return value;    
    }    
    public void setValue(Object  value) {    
        this.value = value;    
    }    
} 

因爲在Pair<T>中,T是一個無限定的類型變量,所以用Object替換。如果是Pair<T extends Number>,擦除後,類型變量用Number類型替換。

public class ReflectInGeneric {  
    public static void main(String[] args) throws IllegalArgumentException,   
                        SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {    
        ArrayList<Integer> array=new ArrayList<Integer>();    
        array.add(1);//這樣調用add方法只能存儲整形,因爲泛型類型的實例爲Integer    
        array.getClass().getMethod("add", Object.class).invoke(array, "asd");    
        for (int i=0;i<array.size();i++) {    
            System.out.println(array.get(i));    
        }    
    }    
} 

利用反射促使array向上轉型爲原始類,這種情況下就可以接受String類了。

程序中定義了一個ArrayList<Integer>泛型類型,如果直接調用add方法,那麼只能存儲整形的數據。不過當我們利用反射調用add方法的時候,卻可以存儲字符串。這說明ArrayList<Integer>泛型信息在編譯之後被擦除了,只保留了原始類型,類型變量(T)被替換爲Object,在運行時,我們可以行其中插入任意類型的對象。

注意:不推薦以這種方式操作泛型類型,因爲這違背了泛型的初衷(減少強制類型轉換以及確保類型安全)。當我們從集合中獲取元素時,默認會將對象強制轉換成泛型參數指定的類型(這裏是Integer),如果放入了非法的對象這個強制轉換過程就會出現異常。

如果不指定泛型類型,編譯器將根據輸入的參數自動識別。對於輸入參數類型不一致的情況,採用幾種參數類型的共同父類的最小級,直到Object。
public class Test {   
    public static void main(String[] args) {    
        /**不指定泛型的時候*/    
        int i=Test.add(1, 2); //這兩個參數都是Integer,所以T替換爲Integer類型    
        Number f=Test.add(1, 1.2);//這兩個參數一個是Integer,另一個是Float,所以取同一父類的最小級,爲Number    
        Object o=Test.add(1, "asd");//這兩個參數一個是Integer,另一個是String,所以取同一父類的最小級,爲Object  
    
        /**指定泛型的時候*/    
        int a=Test.<Integer>add(1, 2);//指定了Integer,所以只能爲Integer類型或者其子類    
        int b=Test.<Integer>add(1, 2.2);//編譯錯誤,指定了Integer,不能爲Float    
        Number c=Test.<Number>add(1, 2.2); //指定爲Number,所以可以爲Integer和Float    
    }    
        
    //這是一個簡單的泛型方法    
    public static <T> T add(T x,T y){    
        return y;    
    }   
}  

重點理解:java編譯器是通過先檢查代碼中泛型的類型,然後再進行類型擦除,再進行編譯的。

泛型相關面試題(轉載)

1. Java中的泛型是什麼 ? 使用泛型的好處是什麼?
泛型是一種參數化類型的機制。它可以使得代碼適用於各種類型,從而編寫更加通用的代碼,例如集合框架。

泛型是一種編譯時類型確認機制。它提供了編譯期的類型安全,確保在泛型類型(通常爲泛型集合)上只能使用正確類型的對象,避免了在運行時出現ClassCastException。

2、Java的泛型是如何工作的 ? 什麼是類型擦除 ?
泛型的正常工作是依賴編譯器在編譯源碼的時候,先進行類型檢查,然後進行類型擦除並且在類型參數出現的地方插入強制轉換的相關指令實現的。

編譯器在編譯時擦除了所有類型相關的信息,所以在運行時不存在任何類型相關的信息。例如List<String>在運行時僅用一個List類型來表示。爲什麼要進行擦除呢?這是爲了避免類型膨脹

3. 什麼是泛型中的限定通配符和非限定通配符 ?
限定通配符對類型進行了限制。有兩種限定通配符,一種是<? extends T>它通過確保類型必須是T的子類來設定類型的上界,另一種是<? super T>它通過確保類型必須是T的父類來設定類型的下界。泛型類型必須用限定內的類型來進行初始化,否則會導致編譯錯誤。另一方面<?>表示了非限定通配符,因爲<?>可以用任意類型來替代。

4. List<? extends T>和List <? super T>之間有什麼區別 ?
這和上一個面試題有聯繫,有時面試官會用這個問題來評估你對泛型的理解,而不是直接問你什麼是限定通配符和非限定通配符。這兩個List的聲明都是限定通配符的例子,List<? extends T>可以接受任何繼承自T的類型的List,而List<? super T>可以接受任何T的父類構成的List。例如List<? extends Number>可以接受List<Integer>或List<Float>。在本段出現的連接中可以找到更多信息。

5. 如何編寫一個泛型方法,讓它能接受泛型參數並返回泛型類型?
編寫泛型方法並不困難,你需要用泛型類型來替代原始類型,比如使用T, E or K,V等被廣泛認可的類型佔位符。泛型方法的例子請參閱Java集合類框架。

{}

面向對象程序設計:https://www.cnblogs.com/1qaz/p/6492465.html

{}

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