java type 简书_Java Type类型

1 Type接口

Java中,JVM会为每一个加载到内存中的类型创建一个Class对象。通过Class对象我们可以获取Field、Constructor、Method、Parameter、Modifier等几乎所有的类的元数据信息,这就是Java中反射的基础,为Java开发提供了很大的灵活性和通用性,是Java语言的一大亮点。

但是遇到泛型类(Generic Class)时,Class就不灵光了。在类型擦除(Type erase)后,Class丢失了泛型类型信息。比如,List和List这两个类型,他们的Class对象是同一个,但是这两个类型又截然不同,这两个类型的变量不能相互赋值,也不能把一个List中的元素存入另一个List。

其实从Java 1.5开始,Java提供了一个Type接口。Type接口是所有类型的公共父接口,包括类和接口(raw types)、参数化类型(parameterized types)、数组类型(array types)、类型变量(type variables)和基本类型(primitive types),可以说,Type是Java语言中的顶级类型接口。Class就实现了Type接口,List和List两个类型的Type信息是不一样的。

有了Type类型,Java开发可以更加灵活,可以写出更加通用的代码。

我们先看看Type接口的定义,它只有一个方法,就是获取Type的字符串名字。

public interface Type {

default String getTypeName() {

return toString();

}

}

下面这些类和接口实现或扩展了Type接口:

graph BT

B[Class]-->type[Type]

C[ParameterizedType]-->type

D[TypeVariable]-->type

E[GenericArrayType]-->type

F[WildcardType]-->type

从上图可以看到,除了Class实现了Type接口,还有四个接口(ParameterizedType、TypeVariable、GenericArrayType、WildcardType)扩展了Type接口。

1.1 Class类

这个大家已经比较熟了,就不多介绍了。它的getTypeName()返回的内容就是Class的全限定域名(fully qualified domain name,FQDN)

1.2 ParameterizedType接口

ParameterizedType接口,跟它的名字一样,参数化类型,表示该类型带有类型参数,比如List这种。它的定义如下:

public interface ParameterizedType extends Type {

Type[] getActualTypeArguments();

Type getRawType();

Type getOwnerType();

}

getActualTypeArguments()方法返回实际的参数类型,因为一个类型可以有多个类型参数,所以是一个数组。比如List类型的这个方法返回的是String类的Class对象(还记得Class实现了Type接口吗?)

getRawType()方法返回擦除类型参数后的类型,比如List类型的这个方法返回的是List类的Class对象

getOwnerType()方法,如果当前类型定义在另一个类型的内部,则返回外部的类型;否则,则是一个顶层类型(top-level type),返回null。比如List类型的这个方法返回的是null,但是Map.Entry类型的这个方法返回的就是Map类的Class对象,因为Entry类定义在Map类的内部

ParameterizedType接口可能是我们使用的最多的Type子接口,毕竟我们使用Type类型,往往是希望知道类型的泛型参数的具体化后的类型。当然ParameterizedType的泛型参数不一定具体化了,它只是表明这个类型包含类型参数。泛型参数是否具体化,可以通过getActualTypeArguments()方法返回的Type类型是Class类型还是其他Type类型来确定。不过这里还存在一个嵌套的问题,比如List>,它的ActualTypeArgument是List,还是一个ParameterizedType

1.3 TypeVariable接口

跟它的名字一样,表示这是一个类型变量。比如类型List中的T就是一个TypeVariable。它的定义如下:

public interface TypeVariable extends Type, AnnotatedElement {

Type[] getBounds();

D getGenericDeclaration();

String getName();

AnnotatedType[] getAnnotatedBounds();

}

通过TypeVariable我们主要通过getBounds()和getName()方法获取它的边界和名字。比如List类型,它的ActualTypeArgument是TypeVariable类型,这个TypeVariable的名字是T,边界是Person Class类型。

1.4 GenericArrayType接口

泛型数组类型接口,它的定义如下:

public interface GenericArrayType extends Type {

Type getGenericComponentType();

}

GenericArrayType接口只有一个getGenericComponentType()方法,返回数组元素的类型,如List[]类型返回的结果是List类型,他是一个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这些表示类的元数据对象获取,因为Field、Method、Constructor、Parameter只能通过Class间接获取,所以Type信息都是从Class获取的。

上述对象获取Class信息的接口,接口名前带有generic前缀的往往就是获取相应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 {

}

public class Class2 {

}

public class Class1 extends Class2 implements Interface1, Interface2 {

}

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");

打印结果:

=====begin print genericSuperclass

type.getTypeName(): com.javatest.generic.Class2

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");

打印结果:

=====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

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 获取类型参数的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");

打印结果:

=====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 {

String str;

List strList1;

List 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");

打印结果:

=====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

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

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的例子应该知道怎么回事了,后面不再给出例子,只给出获取Type信息的方法

2.3.1 方法参数的Type: getGenericParameterTypes()

2.3.2 方法返回值的Type: getGenericReturnType()

2.3.3 方法声明的抛出异常的Type: getGenericExceptionTypes()

2.4 Constructor

2.3.1 构造器参数的Type: getGenericParameterTypes()

2.3.2 构造器声明的抛出异常的Type: getGenericExceptionTypes()

2.5 Parameter

2.5.1 参数的Type: getParameterizedType()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值