~~java 反射類型Type學習~~
- 一、Type介紹
- 二、Type的類型
-
- 2.2 參數化類型ParameterizedType
- 2.3 數組類型GenericArrayType
- 2.4 通配符類型WildcardType
- 2.5 基本Class、基本資料類型和數組
- 三 如何擷取字段或參數的Type資訊
-
- 3.1 擷取字段的泛型資訊
- 3.2 擷取方法參數的泛型資訊
- 3.3 擷取運作時變量的泛型資訊
參考文檔:JAVA15語言官方文檔
一、Type介紹
Type是Java 程式設計語言中所有類型的公共進階接口,也就是Java中所有"類型"的接口。官方原話定義如下
官方文檔:Type is the common superinterface for all types in the Java programming language. These include raw types, parameterized types, array types, type variables and primitive types.
這樣的官方描述有點難懂,此處我畫個圖解釋一下。Type其實是和泛型一起出現的,可以說Type就是為了支援泛型。
- 泛型出現之前,我們可以通過Class來确認一個對象的類型,比如ClassA A,那麼A的類型就是ClassA;
- 泛型出現之後,顯然不能通過Class唯一确認一個對象的類型,比如List<ClassA> A,A的Class是List,但是A的類型顯然不僅僅是List,它是由Class類型的List + TypeVariables的ClassA聯合确認的一個Type。
A type variable is an unqualified identifier used as a type in class, interface, method, and constructor bodies.
The types of the Java programming language are divided into two kinds: primitive types and reference types. The primitive types are the boolean type and the numeric types. The numeric types are the integral types byte, short, int, long, and char, and the floating-point types float and double. The reference types are class types, interface types, and array types. There is also a special null type. An object is a dynamically created instance of a class type or a dynamically created array. The values of a reference type are references to objects. All objects, including arrays, support the methods of class Object . String literals are represented by String objects.
二、Type的類型
Type可以分為兩大類:包含TypeVariables和不包含TypeVariables的類型:
- 不包含TypeVariable:包含基本資料類型(int, long等),基本Class(如Object,不包含泛型的類);
- 包含TypeVariable,按照包含的TypeVariable又分為以下幾類:
- ParameterizedType: 表示一種參數化的類型,如List<String>,泛型的參數已經指定;
- GenericArrayType: 表示一種元素類型是參數化類型或者類型變量的數組類型,如List<String>[][];
- WildcardType: 代表一種通配符類型表達式,比如List<?>, List<? extends ClassA>, List<? super Object>。
繼續介紹Type之前,需要先介紹一下java的泛型機制:
泛型是Java SE 1.5的新特性,泛型的本質是參數化類型,也就是說所操作的資料類型被指定為一個參數。這種參數類型可以用在類、接口和方法的建立中,分别稱為泛型類、泛型接口、泛型方法。 Java語言引入泛型的好處是安全簡單。泛型的好處是在編譯的時候檢查類型安全,并且所有的強制轉換都是自動和隐式的,以提高代碼的重用率。
泛型資訊隻存在于代碼編譯階段,在進入 JVM 之前,與泛型相關的資訊會被擦除掉,專業術語叫做類型擦除。
2.2 參數化類型ParameterizedType
參數化類型的寫法如下:C<T1,…,Tn>,其中C是Class類型,<T1,…,Tn> 是Type,先列幾個參數化類型的合法定義:
Seq<String>
Seq<Seq<String>>
Seq<String>.Zipper<Integer>
Pair<String,Integer>
ParameterizedType類型的接口方法介紹:
傳回值 | 方法名稱 | 描述資訊 |
---|---|---|
Type[] | getActualTypeArguments() | 參數化類型中的TypeVariable參數類型,如List<String> 傳回 String.class, List<List<<String>> 傳回List<<String> |
Type | getOwnerType() | 擷取目前Type所屬的Type,比如對于O<T>.I<S>中的I<S>類型,會傳回 O |
Type | getRawType() | 擷取目前Type的Class,如List<String> 傳回 List.class |
ParameterizedType represents a parameterized type such as Collection<String>.A parameterized type is created the first time it is needed by a reflective method, as specified in this package. When a parameterized type p is created, the generic type declaration that p instantiates is resolved, and all type arguments of p are created recursively. See TypeVariable for details on the creation process for type variables. Repeated creation of a parameterized type has no effect. Instances of classes that implement this interface must implement an equals() method that equates any two instances that share the same generic type declaration and have equal type parameters.
2.3 數組類型GenericArrayType
數組泛型類型的寫法如下:C<T>[],其中C是Class類型,<T> 是Type,先列幾個數組泛型類型的合法定義:
List<String>[]
List<Seq<String>> [][]
傳回值 | 方法名稱 | 描述資訊 |
---|---|---|
Type | getGenericComponentType() | 數組元素的類型,如List<String> []傳回List<String> |
注意:<>不能出現在數組的初始化中,即new數組之後不能出現<>,否則javac無法通過。但是作為引用變量或者方法的某個參數是完全可以的。不包含泛型的數組本節不做介紹(如String[]),下文中會進行介紹。
GenericArrayType represents an array type whose component type is either a parameterized type or a type variable.
2.4 通配符類型WildcardType
通配符類型何其字面意思相同,其泛型類型不再是一個具體的類,而是一個通配符表達式,表達式包含一下三種:"?","? extends Type", “? super Type”,其中Type可以為WildcardType,GenericArrayType,ParameterizedType,Class.
WildcardType represents a wildcard type expression, such as ?, ? extends Number, or ? super Integer.
WildcardType 接口的方法和介紹如下.
傳回值 | 方法名稱 | 描述資訊 |
---|---|---|
Type[] | getLowerBounds() | 傳回通配Type的下限類型,現階段傳回值的長度為1 |
Type[] | getUpperBounds() | 傳回通配Type的上限類型,現階段傳回值的長度為1 |
2.5 基本Class、基本資料類型和數組
通過反射擷取基本的Class和基本資料類型此處就不詳細介紹了,接下來會重點介紹一下數組類型。java的數組類型由虛拟機生成,虛拟機生成的數組類型的名稱一般類似于"class [[Ljava.lang.String;",注意其中的"[["表示是二維數組。那麼如何擷取數組中的元素類型呢? java.lang.Class包中提供了以下接口查詢:
傳回值 | 方法名稱 | 描述資訊 |
---|---|---|
Class<?> | componentType() | 如果類型是數組類型,傳回數組中元素的類型,否則傳回null |
componentType():Returns the component type of this Class, if it describes an array type, or null otherwise.
三 如何擷取字段或參數的Type資訊
平時使用java程式的過程中,我們接觸到的最多的類型隻有Class,像泛型類型和數組類型,通常隻有通過反射才能擷取到。
3.1 擷取字段的泛型資訊
如下程式中,我們首先定義了一個自定義的類TestParameterizedType,隻包含一個字段List<String> field,然後我們在另外一個單測執行個體中嘗試通過反射擷取field的相關資訊。通過field.getType()我們擷取到了field的類型。通過field.getGenericType()我們擷取到了field的泛型資訊。
public class ReflectParameterizedTypeTest {
public static class TestParameterizedType {
private List<String> field;
}
@Test
public void testIntType() throws NoSuchFieldException {
Class<?> clazz = TestParameterizedType.class;
Field field = clazz.getDeclaredField("field");
// 此處擷取到字段的實際Class類型
Class<?> clazzType = field.getType();
System.out.println("Field type: " + clazzType.getName());
// 此處擷取到字段的泛型類型
Type genericType = field.getGenericType();
System.out.println("Field generic type: " + field.getGenericType().getTypeName());
}
}
3.2 擷取方法參數的泛型資訊
類似于字段的擷取方式,方法可以通過Method.getGenericParameterTypes()擷取所有參數的泛型資訊。
3.3 擷取運作時變量的泛型資訊
不可能,具體原因參考java的泛型擦除原理。