不要再稀里糊涂的使用反射了,四万字带你搞定Java反射(JDK8)

前言

阅读本文要求对Java和JVM具有一定程度的了解,请先看下面几个基础问题:

  • 一个类的加载过程是怎样的?
  • 泛型的实现原理是什么?
  • 协变返回类型是什么?
  • 桥接方法是什么?
  • 实例方法和内部类构造函数第一个隐藏参数分别是什么?

如果不能回答出以上问题,建议再复习一下Java语法。通过本文你将彻底掌握反射。

Java反射体系概述

类加载器通过一个类的全限定类名加载此类的字节码文件,并将字节码文件的静态存储结构转化为元空间的运行时数据结构,接着在堆中生成一个代表这个类的java.lang.Class对象作为元空间这个类的各种元数据的接口,我们可以在程序中获取类的Class对象,从而获得在运行时分析类的能力,这就是反射。

在这里插入图片描述

Class代表Java中的类、接口、枚举、注解(以上这些不含类型变量的类型被称为原始类型)、数组和基本类型。这在没有泛型之前完全够用,但在泛型加入后,由于其擦除方式的实现,导致泛型信息不被保存到字节码文件中,此时Class就不太够用了,因此我们会发现一个有趣的事情,Class是JDK1的API,但却实现了来自JDK5的三个接口。其中TypeGenericDeclaration接口就用于协助Clss获取泛型信息。

Type
Class
GenericDeclaration
AnnotatedElement

JDK5后又加入了一个全新的原始类型——注解。注解十分的特殊,它既是一种类型,又可以作为一种标记并几乎可以添加到Java类的任何位置。AnnotatedElement接口就代表Java中所有可以被注解的元素。

类型信息(Type)

Type
Class
ParameterizedType
GenericArrayType
TypeVariable
WildcardType
//Type中的方法
String	getTypeName()//获取类型的描述字符串

Type是Java中所有类型的超级接口。这些类型包括:

  • 原始类型:即不含类型参数的类、接口、枚举和注解。
  • 基本类型:即八种基本类型。
  • 参数化类型:即含有类型参数的类和接口。
  • 数组类型:即数组。
  • 类型变量:即泛型定义时的类型变量。
  • 通配符类型:即通配符类型。

Class只能获取原始类型和基本类型的完整类型信息,如果使用Class获取其它类型的类型信息那么只能获取其擦除后类型(也就是擦除后对应的原始类型)的类型信息。为此Type框架提供四个子接口用于封装被泛化的类型,并在其中提供方法用于获取那些Class获取不到类型信息。这四个子接口分别是:

  • ParameterizedType:参数化类型的封装接口。
Type[] getActualTypeArguments()//获取参数化类型的类型参数的类型
Type getRawType()//获取参数化类型对应的原始类型
Type getOwnerType()//获取参数化类型的所属类型,没有返回null
  • GenericArrayType:数组类型中泛型数组的封装接口。
Type getGenericComponentType()//获取数组的成员类型
  • TypeVariable<D extends GenericDeclaration>:类型变量的封装接口。
D getGenericDeclaration()//获取声明该类型变量的类型
Type[] getBounds()//获取类型变量的约束列表的类型
String getName()//获取类型变量名
  • WildcardType:通配符类型的封装接口。
Type[] getLowerBounds()//获取通配符下界的类型
Type[] getUpperBounds()//返回通配符上界的类型

GenericDeclaration

GenericDeclaration
Class
Executable
Constructor
Method

GenericDeclaration是所有可以声明泛型的元素,在Java中能声明泛型的元素只有类、方法和构造函数。

TypeVariable<?>[] getTypeParameters()//获取泛型变量

AnnotatedType

AnnotatedType
AnnotatedParameterizedType
AnnotatedArrayType
AnnotatedTypeVariable
AnnotatedWildcardType
//AnnotatedType中的方法
Type getType()//返回该元素的类型

AnnotatedType是Java中所有可以被注解类型的超级接口,通过AnnotatedType可以利用注解作为标记并几乎可以添加到Java类任何位置的特性,间接获取类型信息。AnnotatedType也有四个子接口用于对泛化类型进行封装,它们分别是:

  • AnnotatedParameterizedType:带注解的参数化类型的封装接口。
AnnotatedType[]	getAnnotatedActualTypeArguments()//获取参数化类型的类型参数的AnnotatedType
  • AnnotatedArrayType:带注解的泛型数组的封装接口。
AnnotatedType getAnnotatedGenericComponentType()//获取数组的成员的AnnotatedType

AnnotatedTypeVariable:带注解的类型变量的封装接口。

AnnotatedType[]	getAnnotatedBounds()//获取类型约束列表的AnnotatedType
  • AnnotatedWildcardType:带注解的通配符类型的封装。
AnnotatedType[]	getAnnotatedLowerBounds()//获取通配符下界的AnnotatedType
AnnotatedType[]	getAnnotatedUpperBounds()//返回通配符上界的AnnotatedType

AnnotatedType框架与Type框架在结构上极其相似,但具有两种根本性的差异:

  • AnnotatedType既是一个超级接口又代表着可注解的原始类型和基本类型;Type仅是一个超级接口,它的实现类Class代表原始类型和基本类型。
  • AnnotatedType框架具有潜在性。以一个List<Integer>字段为例,当我们获取它的AnnotatedType时,即使它没有被注解,也会返回一个AnnotatedParameterizedType实例。

两者之间的对应关系如下:

在这里插入图片描述

成员信息(Member)

Member
Executable
Field
Constructor
Method

Member是所有成员的超级接口,一个类的成员只有三种:字段(Field)、构造函数(Constructor)和方法(Method)。Member提供的方法如下:

Class<?> getDeclaringClass()//获取声明该成员的类或接口
int	getModifiers()//获取该成员的修饰符
String getName()//获取该成员的名称
boolean	isSynthetic()//判断该成员是否由编译器自动生成

其中构造函数(Constructor)和方法(Method)都是可执行的,并实现了Executable接口,Executable提供的方法如下:

//获取声明异常的Class数组
Class<?>[] getExceptionTypes()
//获取声明异常的Type数组
Type[] getGenericExceptionTypes()
//获取声明异常的AnnotatedType数组
AnnotatedType[]	getAnnotatedExceptionTypes()

//获取参数的Class数组
Class<?>[] getParameterTypes()
//获取参数的Type数组
Type[] getGenericParameterTypes()
//获取参数的AnnotatedType数组
AnnotatedType[]	getAnnotatedParameterTypes()
//获取参数的数量
int	getParameterCount()
//获取参数的Parameter数组
Parameter[]	getParameters()
//获取参数的注解数组
Annotation[][] getParameterAnnotations()
//获取返回值的AnnotatedType 
AnnotatedType getAnnotatedReturnType()

//获取接收器参数
//所谓接收器参数就是默认传入的参数,实例方法的接收器参数就是this
AnnotatedType getAnnotatedReceiverType()

//获取泛型变量数组
TypeVariable<?>[] getTypeParameters()

//是否有可变参数
boolean	isVarArgs()

//返回一个含有任何类型信息的该可执行元素的描述字符串
String toGenericString()

每个类的成员都有自己权限修饰符,当我们使用FieldConstructorMethod来获取字段值或执行方法时也会被它们自身的权限修饰符所约束,为了让反射更加的强大,JVM提供了AccessibleObject接口,通过该接口就可以抑制成员的访问权限。

AccessibleObject
Executable
Field
Constructor
Method

AccessibleObject接口提供的方法如下:

//判断该成员是否可以访问
boolean	isAccessible()

//设置该成员是否可以访问
void setAccessible(boolean flag)
//静态方法,批量设置成员是否可以访问
static void	setAccessible(AccessibleObject[] array, boolean flag)

属性信息(Field)

Field提供关于类或接口的单个字段的信息和动态访问。这些字段可以是静态字段或实例字段。Field允许在getset访问操作期间发生拓宽转换,但如果发生窄化转换,则抛出异常。Field提供的方法如下:

Class<?> getType()
Type getGenericType()
AnnotatedType getAnnotatedType()

Object get(Object obj)
void set(Object obj, Object value)
boolean	getBoolean(Object obj)
void setBoolean(Object obj, boolean z)
byte getByte(Object obj)
void setByte(Object obj, byte b)
char getChar(Object obj)
void setChar(Object obj, char c)
double getDouble(Object obj)
void setDouble(Object obj, double d)
float getFloat(Object obj)
void setFloat(Object obj, float f)
int	getInt(Object obj)
void setInt(Object obj, int i)
long getLong(Object obj)
void setLong(Object obj, long l)
short getShort(Object obj)
void setShort(Object obj, short s)

//判断该字段是否是枚举类型元素
boolean	isEnumConstant()

//返回一个含有任何类型信息的该可执行元素的描述字符串
String toGenericString()

构造函数信息(Constructor)

Constructor提供关于类的单个构造函数的信息和访问。Constructor允许在实例化时将实际形参进行拓宽转换,但如果发生窄化转换,则抛出异常。Constructor提供的方法如下:

TypeVariable<Constructor<T>>[] getTypeParameters()

//使用此constructor对象表示的构造函数,用指定的初始化参数创建和初始化构造函数的声明类的新实例。
//如果构造函数的声明类是非静态上下文中的内部类,构造函数的第一个参数需要是封闭实例.
//如果所需的访问和参数检查成功,实例化将继续,如果构造函数的声明类尚未初始化,则初始化它。
//如果构造函数正常完成,则返回新创建并初始化的实例。
T newInstance(Object... initargs)

方法信息(Method)

Method提供关于类或接口上单个方法的信息和访问。该方法可以是类方法或实例方法。Method允许在调用方法时将实际形参进行拓宽转换,但如果发生窄化转换,则抛出异常。Method提供的方法如下:

//如果该方法的是注解的成员,则返回该成员的默认值
Object getDefaultValue()

//在具有指定参数的指定对象上调用此method对象表示的底层方法。
//如果方法是静态的,那么指定的obj参数将被忽略。也可以是null。
//如果方法所需的形式形参的数量为0,则提供的args数组的长度可以为0或null。
//如果方法是实例方法,则使用动态方法查找调用它,
//如果基础方法是静态的,如果尚未初始化该方法,则初始化声明该方法的类。
//如果方法正常完成,它返回的值返回给调用者。如果值具有基元类型,则将它转换为包装类型;如果值的类型为基元类型的数组,则返回一个原始类型的数组;如果基础方法返回类型为void,则调用返回null。
Object invoke(Object obj, Object... args)

//判断该方法是否是桥接方法
boolean	isBridge()

//判断该方法是否是默认方法
boolean	isDefault()

修饰符信息(Modifier)

Modifier类提供静态方法和常量来解码修饰符。

//修饰符集使用整数表示
static int ABSTRACT
static int FINAL
static int INTERFACE
static int NATIVE
static int PRIVATE
static int PROTECTED
static int PUBLIC
static int STATIC
static int STRICT
static int SYNCHRONIZED
static int TRANSIENT
static int VOLATILE

//返回一个整数表示可以修饰类的修饰符
static int classModifiers()
//返回一个整数表示可以修饰构造函数的修饰符
static int constructorModifiers()
//返回一个修饰符表示可以修饰字段的修饰符
static int fieldModifiers()
//返回一个修饰符表示可以修饰接口的修饰符
static int interfaceModifiers()
//返回一个修饰符表示可以修饰方法的修饰符
static int methodModifiers()
//返回一个修饰符表示可以修饰参数的修饰符
static int parameterModifiers()

static boolean isAbstract(int mod)
static boolean isFinal(int mod)
static boolean isInterface(int mod)
static boolean isNative(int mod)
static boolean isPrivate(int mod)
static boolean isProtected(int mod)
static boolean isPublic(int mod)
static boolean isStatic(int mod)
static boolean isStrict(int mod)
static boolean isSynchronized(int mod)
static boolean isTransient(int mod)
static boolean isVolatile(int mod)

//返回一个字符串,描述指定修饰符中的访问修饰符标志。
static String toString(int mod)

参数信息(Parameter)

Parameter提供关于方法参数的信息,包括其名称和修饰符。它还提供了获取参数属性的替代方法。

Executable getDeclaringExecutable()
int	getModifiers()
String getName()
Type getParameterizedType()
Class<?> getType()
boolean	isImplicit()
boolean	isNamePresent()
boolean	isSynthetic()
boolean	isVarArgs()

注解信息(AnnotatedElement)

AnnotatedElement
Class
Parameter
AccessibleObject
AnnotatedType
TypeVariable
GenericDeclaration

AnnotatedElement接口将注解分成不同的类型,如果有一个可重复的注解元素Parent,它包含的注解元素为Child,现有一个被注解元素E,则Parent的类型根据情况可分为:

  • 直接存在的注解:Parent直接出现在E上
  • 间接存在的注解:Child直接出现在E上
  • 存在的注解:Parent直接出现在E上或Parent是可继承的并出现在E的父类上
  • 关联的注解:Parent直接出现在E上或Child直接出现在E上或Parent是可继承的并出现在E的父类上
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
Annotation[] getAnnotations()
default <T extends Annotation> T[]	getAnnotationsByType(Class<T> annotationClass)
default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)
Annotation[] getDeclaredAnnotations()
default <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass)
default boolean	isAnnotationPresent(Class<? extends Annotation> annotationClass)

不同的方法用于获取不同类型的注解,它们的对应关系如下:

方法名称直接存在的注解间接存在的注解存在的注解关联的注解
getAnnotation
getAnnotations
getAnnotationsByType
getDeclaredAnnotation
getDeclaredAnnotations
getDeclaredAnnotationsByType

Class

  • 方式一:原始类型、数组类型和基本类型可直接使用类名.class的形式:

  • 方式二:Class提供的静态方法forName

//使用指定类加载器加载指定全限定名的类或接口,并只有在initialize为true时才进行初始化
static Class<?> forName(String name,boolean initialize,ClassLoader loader)
//等价于Class.forName(className, true, currentLoader)
static Class<?> forName(String className)
  • 方式三:Object提供的方法getClass
final native Class<?> getClass()
  • 方式四:ClassLoader提供的loadClass方法
//此方式加载的类不会被初始化
Class<?> loadClass(String name) 

Class提供的方法如下:

<U> Class<? extends U> asSubclass(Class<U> clazz)
//将对象强制转换为由此Class对象表示的类或接口
T cast(Object obj)
boolean	desiredAssertionStatus()
//获取加载此类型的类加载器
ClassLoader	getClassLoader()
T newInstance()

//获取该类父接口的Class数组
Class<?>[] getInterfaces()
//获取该类父接口的Type数组
Type[] getGenericInterfaces()
//获取该类父接口的AnnotatedType数组
AnnotatedType[]	getAnnotatedInterfaces()

//获取该类父类的Class对象
Class<? super T> getSuperclass()
//获取该类父类的Type对象
Type getGenericSuperclass()
//获取该类父类的AnnotatedType对象
AnnotatedType getAnnotatedSuperclass()

//查找指定名称的资源
InputStream getResourceAsStream(String name)
URL getResource(String name)

//获取该类型的名称
String getName()
//获取该类的简单名称
String getSimpleName()
//返回由Java语言规范定义的基础类的规范名称。
String getCanonicalName()

//获取该类声明的泛型变量
TypeVariable<Class<T>>[] getTypeParameters()
//获取该类的签名者
Object[] getSigners()
//返回该类的ProtectionDomain。
ProtectionDomain getProtectionDomain()

//返回表示数组的组件类型的Class
Class<?> getComponentType()
//返回此enum类的元素,如果此class对象不表示enum类型,则返回null。
T[]	getEnumConstants()

//获取该类或接口的修饰符
int getModifiers()
//获取该类的包
Package	getPackage()
//获取声明该类或接口类的Class
Class<?> getDeclaringClass()

//如果当前类是匿名内部类,返回它的外围类
Class<?> getEnclosingClass()
//如果当前类是构造函数中的匿名内部类,返回它的外围构造函数
Constructor<?> getEnclosingConstructor()
//如果当前类是方法中的匿名内部类,返回它的外围方法
Method getEnclosingMethod()

//获取一个指定公共字段
Field getField(String name)
//获取一个指定的公共构造函数
Constructor<T> getConstructor(Class<?>... parameterTypes)
//获取一个指定公共方法
Method getMethod(String name,Class<?>... parameterTypes)
//获取所有公共字段
Field[] getFields()
//获取所有公共构造函数
Constructor<?>[] getConstructors()
//获取所有公共方法
Method[] getMethods()
//获取由此类公共的内部类和接口
Class<?>[] getClasses()
//获取一个指定字段
Field getDeclaredField(String name)
//获取一个指定构造函数
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
//获取一个指定方法
Method getDeclaredMethod(String name,Class<?>... parameterTypes)
//获取所有字段
Field[] getDeclaredFields()
//获取所有构造函数
Constructor<?>[] getDeclaredConstructors()
//获取所有方法
Method[] getDeclaredMethods()
//获取由此类所有内部类和接口
Class<?>[] getDeclaredClasses()

//判断该类是否是注解类型
boolean	isAnnotation()
//判断该类是否是匿名类
boolean	isAnonymousClass()
//判断该类是否是数组
boolean	isArray()
//是否是枚举
boolean	isEnum()
//判断指定对象是否是与此类兼容
boolean	isInstance(Object obj)
//判断该类是否是与指定类型相同或是指定类型的超类型
boolean	isAssignableFrom(Class<?> cls)
//是否是接口
boolean	isInterface()
//是否是本地类
boolean	isLocalClass()
//是否是内部类
boolean	isMemberClass()
//是否是原始类型
boolean	isPrimitive()
//是否是自动生成的类
boolean	isSynthetic()

//获取含有任何类型信息的该类的描述符
String toGenericString()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亻乍屯页女子白勺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值