Java泛型筆記
泛型的使用可以避免編寫過多的冗餘程式碼,相對於之前的使用Object類來說,更加健壯(型別安全),將型別的強轉放到了編譯期(之前型別的檢查和型別的強轉都必須由程式設計師自己負責),減少了很多由於型別轉換出現的執行時錯誤的出現。
Java中的泛型有兩種應用,一種是泛型類,另外一種是泛型方法。
關於泛型的一些內容,可以參考這篇部落格:https://blog.csdn.net/s10461/article/details/53941091 ,總結的比較詳細。
這裡主要想記錄一下關於泛型的擦除機制,事實上,在JVM中是看不到泛型的,所有的泛型在編譯階段就已經被處理成了普通類和方法。 ‘
可以這麼理解:在泛型類或者泛型方法在被編譯器進行編譯的時候,傳入的型別引數被擦除掉,轉而用一個叫“原始型別”的來替換被擦掉的型別資訊。無論我們如何定義一個泛型型別,相應的都會有一個原始型別在編譯的時候被自動提供。
// 擦除前
public class A<T> {
private T t;
public T getT(){
return t;
}
}
// 擦除後
public class A{
private Object t;
public Object getT(){
return t;
}
}
或者可以直接檢視編譯後的位元組碼檔案,可以更加明顯的看出泛型引數T,被替換成Object
// class version 52.0 (52)
// access flags 0x21
// signature <T:Ljava/lang/Object;>Ljava/lang/Object;
// declaration: A<T>
public class A {
// compiled from: A.java
// access flags 0x2
// signature TT;
// declaration: t extends T
private Ljava/lang/Object; t
// access flags 0x1
public <init>()V
L0
LINENUMBER 1 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
RETURN
L1
LOCALVARIABLE this LA; L0 L1 0
// signature LA<TT;>;
// declaration: this extends A<T>
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1
// signature ()TT;
// declaration: T getT()
public getT()Ljava/lang/Object;
L0
LINENUMBER 5 L0
ALOAD 0
GETFIELD A.t : Ljava/lang/Object;
ARETURN
L1
LOCALVARIABLE this LA; L0 L1 0
// signature LA<TT;>;
// declaration: this extends A<T>
MAXSTACK = 1
MAXLOCALS = 1
}
值得注意的是:如果泛型是使用無限定的方式指定(沒有使用 <T extends Number>等形式),擦除後的原始型別就是Object,但是當使用了限定符後就不是這樣了,例如ArrayList<? extends Number>,擦除的時候是會被替換為限定型別Number,而不是Object。
也正是由於泛型的擦除機制,下面的這段程式碼才會輸出true,這是因為擦除後的ArrayList不帶有泛型資訊,他們的Class都是ArrayList
ArrayList<String> list1 = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>();
System.out.println(list1.getClass() == list2.getClass());
// true
System.out.println(list1.getClass());
// class java.util.ArrayList
System.out.println(list2.getClass());
// class java.util.ArrayList
對於上面的提到的那篇部落格中說的泛型陣列的問題,在明白了型別擦除之後,就很容易搞明白了。
在泛型類的內部,不能直接使用new T()來例項化一個T型別的物件,但是我們可以利用Java的反射機制來獲取實際的型別引數的型別。
可以通過另一個類來繼承這個泛型類,然後使用下面的方式來獲得泛型類中傳入的實際型別的名字,這在Java web中,比如在編寫BaseDao<T>的時候被使用到。
class TestA<T>{
private Class clazz;
public TestA(){
Type type = this.getClass().getGenericSuperclass();
ParameterizedType parameterizedType = (ParameterizedType) type;
clazz = (Class) parameterizedType.getActualTypeArguments()[0];
System.out.println(clazz);
}
}
class TestB extends TestA<String>{
public TestB(){
System.out.println("TestB被呼叫了");
}
}
其他由於Java泛型的擦除機制帶來的問題,可以參考《Java核心技術 卷1》中的12.5的相關內容。
相關文章
- java筆記-two-java泛型程式設計(簡記)Java筆記泛型程式設計
- 泛型學習筆記泛型筆記
- Java集合 Collection、Set、Map、泛型 簡要筆記Java泛型筆記
- 【java】【泛型】泛型geneticJava泛型
- Java泛型Java泛型
- iOS學習筆記47 Swift(七)泛型iOS筆記Swift泛型
- Java-泛型Java泛型
- Java(7)泛型Java泛型
- Java+泛型Java泛型
- Java 泛型原理Java泛型
- java泛型一二Java泛型
- 《Java核心技術(卷1)》筆記:第8章 泛型程式設計Java筆記泛型程式設計
- Java™ 教程(泛型原始型別)Java泛型型別
- Java基礎 —— 泛型Java泛型
- Java中的泛型Java泛型
- Java基礎-泛型Java泛型
- JAVA泛型入門Java泛型
- Java 泛型詳解Java泛型
- Java:Collection集合、泛型Java泛型
- Java泛型知識Java泛型
- 淺談java泛型Java泛型
- java 基礎 泛型Java泛型
- Java泛型複習Java泛型
- 認識Java泛型Java泛型
- Java函式泛型List引數,操作泛型元素Java函式泛型
- 【Java反射】Java 泛型基礎Java反射泛型
- Java泛型型別擦除問題Java泛型型別
- 再次認識java泛型Java泛型
- Java & Go 泛型對比JavaGo泛型
- Java的泛型機制Java泛型
- Java高階特性—泛型Java泛型
- Java泛型的那些事Java泛型
- Android、Java泛型掃盲AndroidJava泛型
- JAVASE之JAVA泛型篇Java泛型
- Java中的泛型方法Java泛型
- 深入理解 Java 泛型Java泛型
- Java泛型及實踐Java泛型
- 我理解的 Java 泛型Java泛型