Java 反射机制包 java.lang.reflect

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包文档

你可能感兴趣的:(Java,学习总结)