首頁  >  文章  >  Java  >  說說java的泛型機制是怎麼樣的

說說java的泛型機制是怎麼樣的

王林
王林轉載
2021-01-27 09:59:062110瀏覽

說說java的泛型機制是怎麼樣的

面試官:說一下java的泛型機制是怎麼樣的。

(學習影片分享:java影片教學

精簡版回答

Java在開發時,透過使用菱形語法6d267e5fab17ea8bc578f9e7e5e1570b,使一個類別、介面或方法具有接受泛指的一群類別作為參數,泛指的類別最終由尖括號裡的規則所限定,泛指類別通常用大寫字母表示,一般用字母T,後期經過Java編譯器編譯,泛型將被擦除,根據具體使用的類,替換泛型,產生class字節碼,所以泛型是對Jvm透明的。

豪華版回答

泛型於JDK1.5正式引入

#Java引入泛型背景

Java集合是允許放入多種類型的,例如

    List list=new ArrayList();
    list.add("String");
    list.add(1024);

這在JDK1.5之前是常見的使用方式,即便放在今天的JDK下,也是允許的,那麼類似於這種集合的使用方式,就會帶來一些問題,就是集合中究竟放了哪些類型,恐怕只有創建集合的人才知道,其他調用者,根本無法確定,這樣在大型項目裡,極易出現問題,調用者強轉集合裡的某個對象,一旦類型錯誤,就會報錯,這種錯在當時編譯階段是無法發現的,只有執行時才被發現,為了解決類似問題,JDK引進了泛型。

泛型類型

引入泛型後,因此可以在編譯階段,檢查型別是否符合要求,很大程度上,杜絕了盲目的型別轉換。 泛型主要工作在編譯器,編譯後,JVM執行時,是無法感知泛型的。 泛型分為普通泛型和通配泛型。

1.普通泛型

這類泛型顧名思義,就是支援呼叫時傳入任意型別,但是呼叫時,等號左右兩邊泛型必須一致。 JDK1.7右側菱形可以省略。

class Test<T>{...} //声明时
Test<Integer> test = new Test<Integer>(); //调用时
Test<Integer> test = new Test(); //1.7调用时

3.界限泛型

<?>//无界泛型,任意类型都匹配
<T extends ClassA>//有界泛型 - 继承自某父类
<T extends InterfaceB>//有界泛型 - 实现某接口
<T extends ClassA & InterfaceB & InterfaceC ... >//有界泛型 - 多重边界
<T super ClassC>//有界泛型 - 指定类父类

泛型擦除

#剛才說到,泛型只在寫程式碼時和編譯時起作用,而Jvm則載入class運行時是無感透明的,是因為編譯器編譯時將泛型擦除了,簡單不嚴謹的說就是:把類別或方法上的那個a8093152e673feb7aba1828c43532094尖括號幹掉了,根據尖括號裡的規則換成具體的類,所以Jvm運行時根本不知道這段程式碼里之前有過泛型,這樣做是為了兼容,前面說到泛型是JDK1.5才引入的,這樣,即便引入泛型,現有的Jvm也不需要大改,只要改一下編譯器即可,對於這種編譯器能感知的語法,而虛擬機無法感知的,人們把這種語法稱作語法糖(suger),編譯器經過脫糖(Desuger) 後,拿到乾貨,交給虛擬機器去執行。

(圖文教學推薦:java入門教學

泛型擦除機制

//Pair的泛型
public class Pair<T> {

    private T mFirst;
    private T mSecond;

    public T getmFirst() {
        return mFirst;
    }

    public void setmFirst(T mFirst) {
        this.mFirst = mFirst;
    }

    public T getmSecond() {
        return mSecond;
    }

    public void setmSecond(T mSecond) {
        this.mSecond = mSecond;
    }
}

//Pair的原始类型
//无论何时定义一个泛型类型,都会自动提供一个相应的 原始类型
public class Pair {

    private Object mFirst;
    private Object mSecond;

    public Object getFirst() {
        return mFirst;
    }

    public void setFirst(Object mFirst) {
        this.mFirst = mFirst;
    }

    public Object getSecond() {
        return mSecond;
    }

    public void setmSecond(Object mSecond) {
        this.mSecond = mSecond;
    }
}

//如果调用Pair<T extends String>编译擦除后得到如下=
class Pair{
    private String mFirst;
    private String mSecond;
    ...
}

當泛型作為方法的入參時,擦除後換成通配泛型的下界,例如add方法

public static void insertElements(List<? super A> list){
    //Add进来的都是层级“小于等于”A的,也就是下界
    list.add(new A());
    list.add(new B());
    list.add(new C());
}

當泛型作為方法的回參時,擦除後換成通配泛型的上界,例如get方法

public void processElements(List<? extends A> elements){
   //for循环挨个get list 里的数据,都当做A,也就是都当做上界
   for(A a : elements){
      System.out.println(a.getValue());
   }
}

對於泛型的類型擦除說再多,看再多博客,不如官方定義準確,放一段Oracle官方對於類型擦除的文檔

Type Erasure
Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to:
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.Insert type casts if necessary to preserve type safety.Generate bridge methods to preserve polymorphism in extended generic types.Type erasure ensures that no new classes are created for parameterized types; consequently, generics incur no runtime overhead.

更多面試題請點擊: java面試題目及答案

#

以上是說說java的泛型機制是怎麼樣的的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.im。如有侵權,請聯絡admin@php.cn刪除