Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。
我们知道对于一个类或者说是class文件比较准确,是JVM将描述的类的数据从class文件加载到内存(方法区),并且对数据进行校验和初始化,最终形成可以被虚拟机直接使用的Java类型。其实对于任何一个Java中的任意一个类型,都有一个对应的Class对象用于描述该类的数据,Class是Java反射机制的核心API,它是我们获取类数据的基础。一般来说,我们有三种方法去获取一个类的Class对象:
package cn.org.microservice.java.reflection;
//创建一个类,然后获取该类的Class对象
public class Reflection {
.......
//1.通过对象的方式获取
Reflection reflection = new Reflection();
Class clazz1 = reflection.getClass();
//2.通过Class.forName()获取
String className = "cn.org.microservice.java.reflection.Reflection";
Class clazz2 = Class.forName(className);
//3.直接通过类型.class获取
Class clazz3 = Reflection.class;
//4.通过 通过ClassLoader的loadClass()获取
Class clazz4 = ClassReflection.class.getClassLoader().loadClass(className);
//代码中clazz1,clazz2.clazz3.clazz4指向的是同一个Class对象
//打印出的的是同一个对象
System.out.println(clazz1 + "," + clazz2 + "," + clazz3+ "," + clazz4);
System.out.println(clazz1.hashCode() + "," + clazz2.hashCode()+ "," + clazz3.hashCode() + "," + clazz4.hashCode());
}
每一个类都会对应且只有一个Class实例,这个示例存储这该类的数据信息,包括包(Package),类名称(String),全类名称(String),构造方法(Constructor),方法(Method),字段(Field),父类(Class),接口(Class),注解等相关信息,我么可以在运行时或者这些信息:相关API如下:
public class ClassReflection {
public static void main(String[] args) throws ClassNotFoundException {
String className = "cn.org.microservice.java.reflection.Reflection";
Class clazz1 = Reflection.class;
//获取包信息
Package package1 = clazz1.getPackage();
//获取构造方法信息
Constructor[] constructors = clazz1.getConstructors();
Constructor constructor = clazz1.getConstructor();
//获取字段信息,其中getField只能获取public声明的字段,getDeclaredField可以获取所有字段
Field field = clazz1.getField("name");
Field[] fields1 = clazz1.getFields();
Field field2 = clazz1.getDeclaredField("protectedField");
Field[] fields2 = clazz1.getDeclaredFields();
//获取方法信息 其中getField只能获取getMethod声明的字段,getDeclaredMethod可以获取所有字段
Method Method1 = clazz1.getMethod("setName", String.class);
Method[] Methods1 = clazz1.getMethods();
Method Method2 = clazz1.getDeclaredMethod("privateMethod",int.class);
Method[] Methods2 = clazz1.getDeclaredMethods();
//获取接口信息
Class [] clazzs1 = clazz1.getInterfaces();
Type [] interfacetypes = clazz1.getGenericInterfaces();
//获取父类信息
Class clazzs2 = clazz1.getSuperclass();
Type superClasstypes = clazz1.getGenericSuperclass();
//获取注解信息
Annotation [] auAnnotations = clazz1.getAnnotations();
//获取类的修饰符
clazz1.getModifiers();
//是否是接口
clazz1.isInterface();
//获取全类名
clazz1.getName();
//获取类名
clazz1.getSimpleName();
}
}
Field类:
Field类用于描述Class中的Field的相关信息。我们可以通过getField(s)获取public修饰的字段、getDeclaredField(s)等方法获取非public方法获取的字段。然后通过Field实例获取Field的相关信息:
String className = "cn.org.microservice.java.reflection.Reflection";
Class clazz = Class.forName(className);
Field field = clazz.getField("name");
Reflection r = new Reflection();
// 获取字段名称
field.getName();
// 获取字段上注解
Annotation[] annotations = field.getAnnotations();
//为获取Reflection的字段name的值
field.get(r);
//为Reflection字段name设置值
field.set(r, "pharos");
Constructor类:
Constructor类用于描述Class中的Constructor的相关信息。我们可以通过getConstructor(s)获取public修饰的构造方法、getDeclaredConstructor(s)等方法获取非public修饰的构造方法。然后通过Constructor实例获取Constructor的相关信息,并且可以通过构造方法实例化对象。下面是常用的Constructor API。
//通过无参构造方法实例化对象
Constructor constructor = clazz.getConstructor();
Reflection reflection = (Reflection) constructor.newInstance();
//通过有参构造方法实例化对象
Constructor constructor1 = clazz.getConstructor(String.class);
Reflection reflection1 = (Reflection) constructor1.newInstance("pharos");
Constructor constructor1 = clazz.getConstructor(String.class);
Reflection reflection1 = (Reflection) constructor1.newInstance("pharos");
Constructor constructor2 = clazz.getDeclaredConstructor(int.class);
//如果是非public修饰的构造方法,使用其初始化对象时,需要调用setAccessible,并设置为true,可访问
constructor2.setAccessible(true);
Reflection reflection2 = (Reflection) constructor2.newInstance(10);
//获取构造方法上的注解
constructor.getAnnotations();
//获取构造方法中参数注解
constructor.getParameterAnnotations();
//获取所有参数
constructor.getParameters();
//获取参数数量
constructor.getParameterCount();
//获取参数类型
constructor.getParameterTypes();
Annotation类:一般我们使用getAnnotations()获取到所有注解,然后根据不同的注解类型,做处理。
Annotation [] annotations = Reflection.class.getAnnotations();
for(Annotation annotation : annotations) {
System.out.println(annotation.annotationType());
}
Package类:一把我们使用getPackage()获取一个类的包,也可以通过静态方法getPackages()获取虚拟机加载的所有包。
Package package1 = Reflection.class.getPackage();
System.out.println(package1.getName());
Package [] package2 =Package.getPackages();
for(Package package3 : package2) {
System.out.println(package3.getName());
}
Method类:Method类用于描述Class中的Method的相关信息。我们可以通过getMethod(s)获取public修饰的方法,通过getDeclaredMethod(s)获取非public修饰的方法。
Class clazz1 = Reflection.class;
Method method1 = clazz1.getDeclaredMethod("privateMethod", int.class);
Reflection instance = clazz1.newInstance();
//同构造方法类似,我么可以获取方法上的注解,参数中的注解,参数,参数类型,参数数量
method1.getAnnotations();
method1.getParameterAnnotations();
method1.getParameters();
method1.getParameterCount();
method1.getParameterTypes();
/获取返回值类型
method1.getReturnType();
//我们可以通过invoke方法执行获取到的方法
Method method1 = clazz1.getDeclaredMethod("privateMethod", int.class);
//与构造方法类似,如果是非public修饰的方法,调用前需要设置访问属性为true,
method1.setAccessible(true);
method1.invoke(instance, 10);
其实Java的反射用起来还是比较简单的,就是通过类的Class实例,获取类的数据,然后根据获取到的数据进行处理,详细的Java 反射API 可以参考官方的java.lang.reflect包文档