1 Type接口
Java中水泉,JVM會為每一個加載到內(nèi)存中的類型創(chuàng)建一個Class
對象抱冷。通過Class
對象我們可以獲取Field
汗菜、Constructor
、Method
摧莽、Parameter
庙洼、Modifier
等幾乎所有的類的元數(shù)據(jù)信息,這就是Java中反射的基礎(chǔ)镊辕,為Java開發(fā)提供了很大的靈活性和通用性油够,是Java語言的一大亮點。
但是遇到泛型類(Generic Class)時征懈,Class
就不靈光了石咬。在類型擦除(Type erase)后,Class
丟失了泛型類型信息受裹。比如碌补,List<Integer>
和List<String>
這兩個類型虏束,他們的Class
對象是同一個棉饶,但是這兩個類型又截然不同,這兩個類型的變量不能相互賦值镇匀,也不能把一個List
中的元素存入另一個List
照藻。
其實從Java 1.5開始,Java提供了一個Type
接口汗侵。Type
接口是所有類型的公共父接口幸缕,包括類和接口(raw types)、參數(shù)化類型(parameterized types)晰韵、數(shù)組類型(array types)发乔、類型變量(type variables)和基本類型(primitive types),可以說雪猪,Type
是Java語言中的頂級類型接口栏尚。Class
就實現(xiàn)了Type
接口,List<Integer>
和List<String>
兩個類型的Type
信息是不一樣的只恨。
有了Type類型译仗,Java開發(fā)可以更加靈活抬虽,可以寫出更加通用的代碼。
我們先看看Type
接口的定義纵菌,它只有一個方法阐污,就是獲取Type
的字符串名字。
public interface Type {
default String getTypeName() {
return toString();
}
}
下面這些類和接口實現(xiàn)或擴展了Type
接口:
graph BT
B[Class]-->type[Type]
C[ParameterizedType]-->type
D[TypeVariable]-->type
E[GenericArrayType]-->type
F[WildcardType]-->type
從上圖可以看到咱圆,除了Class
實現(xiàn)了Type
接口笛辟,還有四個接口(ParameterizedType、TypeVariable闷堡、GenericArrayType隘膘、WildcardType)擴展了Type
接口。
1.1 Class類
這個大家已經(jīng)比較熟了杠览,就不多介紹了弯菊。它的getTypeName()
返回的內(nèi)容就是Class
的全限定域名(fully qualified domain name,F(xiàn)QDN)
1.2 ParameterizedType接口
ParameterizedType接口踱阿,跟它的名字一樣管钳,參數(shù)化類型,表示該類型帶有類型參數(shù)软舌,比如List<String>
這種才漆。它的定義如下:
public interface ParameterizedType extends Type {
Type[] getActualTypeArguments();
Type getRawType();
Type getOwnerType();
}
getActualTypeArguments()
方法返回實際的參數(shù)類型,因為一個類型可以有多個類型參數(shù)佛点,所以是一個數(shù)組醇滥。比如List<String>
類型的這個方法返回的是String
類的Class
對象(還記得Class
實現(xiàn)了Type
接口嗎?)
getRawType()
方法返回擦除類型參數(shù)后的類型超营,比如List<String>
類型的這個方法返回的是List
類的Class
對象
getOwnerType()
方法鸳玩,如果當(dāng)前類型定義在另一個類型的內(nèi)部,則返回外部的類型演闭;否則不跟,則是一個頂層類型(top-level type),返回null米碰。比如List<String>
類型的這個方法返回的是null窝革,但是Map.Entry<String, String>
類型的這個方法返回的就是Map
類的Class
對象,因為Entry
類定義在Map
類的內(nèi)部
ParameterizedType
接口可能是我們使用的最多的Type
子接口吕座,畢竟我們使用Type
類型虐译,往往是希望知道類型的泛型參數(shù)的具體化后的類型。當(dāng)然ParameterizedType
的泛型參數(shù)不一定具體化了吴趴,它只是表明這個類型包含類型參數(shù)漆诽。泛型參數(shù)是否具體化,可以通過getActualTypeArguments()
方法返回的Type
類型是Class
類型還是其他Type
類型來確定。不過這里還存在一個嵌套的問題拴泌,比如List<List<String>>
魏身,它的ActualTypeArgument
是List<String>
,還是一個ParameterizedType
1.3 TypeVariable接口
跟它的名字一樣蚪腐,表示這是一個類型變量箭昵。比如類型List<T>
中的T
就是一個TypeVariable
。它的定義如下:
public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
Type[] getBounds();
D getGenericDeclaration();
String getName();
AnnotatedType[] getAnnotatedBounds();
}
通過TypeVariable
我們主要通過getBounds()
和getName()
方法獲取它的邊界和名字回季。比如List<T extends Person>
類型家制,它的ActualTypeArgument
是TypeVariable
類型,這個TypeVariable
的名字是T
泡一,邊界是Person
Class
類型颤殴。
1.4 GenericArrayType接口
泛型數(shù)組類型接口,它的定義如下:
public interface GenericArrayType extends Type {
Type getGenericComponentType();
}
GenericArrayType
接口只有一個getGenericComponentType()
方法鼻忠,返回數(shù)組元素的類型涵但,如List<String>[]
類型返回的結(jié)果是List<String>
類型,他是一個ParameterizedType
1.5 WildcardType接口
表示泛型的通配符(?)類型帖蔓,比如List<?>
中的?
矮瘟。它的定義如下:
public interface WildcardType extends Type {
Type[] getUpperBounds();
Type[] getLowerBounds();
}
WildcardType
接口提供了兩個接口,分別獲取通配符?
的上下邊界塑娇。比如List<? extends Person>
的上邊界是Person
Class
澈侠。List<? super Person>
的下邊界是Person
Class
。
2 獲取Type接口信息
我們可以通過類的全限定域名或類的對象獲取Class
對象埋酬,Type
則可以通過Class
哨啃、Field
、Method
写妥、Constructor
拳球、Parameter
這些表示類的元數(shù)據(jù)對象獲取,因為Field
耳标、Method
醇坝、Constructor
邑跪、Parameter
只能通過Class
間接獲取次坡,所以Type
信息都是從Class
獲取的。
上述對象獲取Class
信息的接口画畅,接口名前帶有generic
前綴的往往就是獲取相應(yīng)Type
信息的接口
下面通過一些實例觀察獲取Type
的一些接口信息砸琅,遞歸打印Type
信息的方法:
public static void printTypeInfo(final Type type) {
log.info("type.getTypeName(): {}", type.getTypeName());
if (type instanceof Class) {
Class c = (Class) type;
log.info("type is Class");
} else if (type instanceof ParameterizedType) {
ParameterizedType t = (ParameterizedType) type;
log.info("type is ParameterizedType");
Type[] actualTypeArguments = t.getActualTypeArguments();
log.info("ParameterizedType.getActualTypeArguments(): {}", Arrays.toString(actualTypeArguments));
for (int i = 0; i < actualTypeArguments.length; i++) {
printTypeInfo(actualTypeArguments[i]);
}
Type rawType = t.getRawType();
log.info("ParameterizedType.getRawType(): {}", rawType);
printTypeInfo(rawType);
Type ownerType = t.getOwnerType();
log.info("ParameterizedType.getOwnerType(): {}", ownerType);
if (ownerType != null) {
printTypeInfo(ownerType);
}
} else if (type instanceof TypeVariable) {
TypeVariable t = (TypeVariable) type;
log.info("type is TypeVariable");
String name = t.getName();
log.info("TypeVariable.getName(): {}", name);
Type[] bounds = t.getBounds();
log.info("TypeVariable.getBounds(): {}", Arrays.toString(bounds));
if (bounds != null) {
for (int i = 0; i < bounds.length; i++) {
printTypeInfo(bounds[i]);
}
}
} else if (type instanceof GenericArrayType) {
GenericArrayType t = (GenericArrayType) type;
log.info("type is GenericArrayType");
Type componentType = t.getGenericComponentType();
log.info("GenericArrayType.getGenericComponentType(): {}", componentType);
printTypeInfo(componentType);
} else if (type instanceof WildcardType) {
WildcardType t = (WildcardType) type;
log.info("type is WildcardType");
Type[] upperBounds = t.getUpperBounds();
log.info("WildcardType.getUpperBounds(): {}", Arrays.toString(upperBounds));
if (upperBounds != null) {
for (int i = 0; i < upperBounds.length; i++) {
printTypeInfo(upperBounds[i]);
}
}
Type[] lowerBounds = t.getLowerBounds();
log.info("WildcardType.getLowerBounds(): {}", Arrays.toString(lowerBounds));
if (lowerBounds != null) {
for (int i = 0; i < lowerBounds.length; i++) {
printTypeInfo(lowerBounds[i]);
}
}
}
}
2.1 Class
用來測試的類:
public interface Interface1 {
}
public interface Interface2<T1, T2> {
}
public class Class2<T> {
}
public class Class1<T, S> extends Class2<S> implements Interface1, Interface2<String, T> {
}
2.1.1 獲取父類的Type
: getGenericSuperclass()
測試代碼:
Class c = Class1.class;
Type genericSuperclass = c.getGenericSuperclass();
log.info("=====begin print genericSuperclass");
if (genericSuperclass != null) {
printTypeInfo(genericSuperclass);
}
log.info("=====finish print genericSuperclass");
打印結(jié)果:
=====begin print genericSuperclass
type.getTypeName(): com.javatest.generic.Class2<S>
type is ParameterizedType
ParameterizedType.getActualTypeArguments(): [S]
type.getTypeName(): S
type is TypeVariable
TypeVariable.getName(): S
TypeVariable.getBounds(): [class java.lang.Object]
type.getTypeName(): java.lang.Object
type is Class
ParameterizedType.getRawType(): class com.javatest.generic.Class2
type.getTypeName(): com.javatest.generic.Class2
type is Class
ParameterizedType.getOwnerType(): null
=====finish print genericSuperclass
2.1.2 獲取父接口的Type
: getGenericInterfaces()
測試代碼:
Type[] genericSuperInterfaces = c.getGenericInterfaces();
log.info("=====begin print genericSuperInterfaces");
if (genericSuperInterfaces != null) {
for (int i = 0; i < genericSuperInterfaces.length; i++) {
log.info("=====begin print genericSuperInterfaces, i={}", i);
printTypeInfo(genericSuperInterfaces[i]);
log.info("=====finish print genericSuperInterfaces i={}", i);
}
}
log.info("=====finish print genericSuperInterfaces");
打印結(jié)果:
=====begin print genericSuperInterfaces
=====begin print genericSuperInterfaces, i=0
type.getTypeName(): com.javatest.generic.Interface1
type is Class
=====finish print genericSuperInterfaces i=0
=====begin print genericSuperInterfaces, i=1
type.getTypeName(): com.javatest.generic.Interface2<java.lang.String, T>
type is ParameterizedType
ParameterizedType.getActualTypeArguments(): [class java.lang.String, T]
type.getTypeName(): java.lang.String
type is Class
type.getTypeName(): T
type is TypeVariable
TypeVariable.getName(): T
TypeVariable.getBounds(): [class java.lang.Object]
type.getTypeName(): java.lang.Object
type is Class
ParameterizedType.getRawType(): interface com.javatest.generic.Interface2
type.getTypeName(): com.javatest.generic.Interface2
type is Class
ParameterizedType.getOwnerType(): null
=====finish print genericSuperInterfaces i=1
=====finish print genericSuperInterfaces
2.1.3 獲取類型參數(shù)的Type
: getTypeParameters()
測試代碼:
TypeVariable[] typeVariables = c.getTypeParameters();
log.info("=====begin print typeVariables");
if (typeVariables != null) {
for (int i = 0; i < typeVariables.length; i++) {
log.info("=====begin print typeVariables, i={}", i);
printTypeInfo(typeVariables[i]);
log.info("=====finish print typeVariables i={}", i);
}
}
log.info("=====finish print typeVariables");
打印結(jié)果:
=====begin print typeVariables
=====begin print typeVariables, i=0
type.getTypeName(): T
type is TypeVariable
TypeVariable.getName(): T
TypeVariable.getBounds(): [class java.lang.Object]
type.getTypeName(): java.lang.Object
type is Class
=====finish print typeVariables i=0
=====begin print typeVariables, i=1
type.getTypeName(): S
type is TypeVariable
TypeVariable.getName(): S
TypeVariable.getBounds(): [class java.lang.Object]
type.getTypeName(): java.lang.Object
type is Class
=====finish print typeVariables i=1
=====finish print typeVariables
2.2 Field
用來測試的類
public class Class2<T> {
String str;
List<String> strList1;
List<T> strList2;
T t1;
}
2.2.1 類屬性的Type
: getGenericType()
測試代碼:
Class c = Class2.class;
log.info("=====begin pring field str");
Field f = c.getDeclaredField("str");
Type type = f.getGenericType();
printTypeInfo(type);
log.info("=====finish pring field str");
log.info("=====begin pring field strList1");
f = c.getDeclaredField("strList1");
type = f.getGenericType();
printTypeInfo(type);
log.info("=====finish pring field strList1");
log.info("=====begin pring field strList2");
f = c.getDeclaredField("strList2");
type = f.getGenericType();
printTypeInfo(type);
log.info("=====finish pring field strList2");
log.info("=====begin pring field t1");
f = c.getDeclaredField("t1");
type = f.getGenericType();
printTypeInfo(type);
log.info("=====finish pring field t1");
打印結(jié)果:
=====begin pring field str
type.getTypeName(): java.lang.String
type is Class
=====finish pring field str
=====begin pring field strList1
type.getTypeName(): java.util.List<java.lang.String>
type is ParameterizedType
ParameterizedType.getActualTypeArguments(): [class java.lang.String]
type.getTypeName(): java.lang.String
type is Class
ParameterizedType.getRawType(): interface java.util.List
type.getTypeName(): java.util.List
type is Class
ParameterizedType.getOwnerType(): null
=====finish pring field strList1
=====begin pring field strList2
type.getTypeName(): java.util.List<T>
type is ParameterizedType
ParameterizedType.getActualTypeArguments(): [T]
type.getTypeName(): T
type is TypeVariable
TypeVariable.getName(): T
TypeVariable.getBounds(): [class java.lang.Object]
type.getTypeName(): java.lang.Object
type is Class
ParameterizedType.getRawType(): interface java.util.List
type.getTypeName(): java.util.List
type is Class
ParameterizedType.getOwnerType(): null
=====finish pring field strList2
=====begin pring field t1
type.getTypeName(): T
type is TypeVariable
TypeVariable.getName(): T
TypeVariable.getBounds(): [class java.lang.Object]
type.getTypeName(): java.lang.Object
type is Class
=====finish pring field t1
2.3 Method
從上面Class
和Field
的例子應(yīng)該知道怎么回事了,后面不再給出例子轴踱,只給出獲取Type
信息的方法