反射-反射的应用

反射的应用

注:clazz是Class的实例,per才是Person的对象!!!

创建运行时类的对象

通过Class实例调用newInstance()方法
  • 条件1:要求运行时类中必须提供一个空参的构造器

  • 条件2:要求提供的空参的构造器的权限要足够

在JDK9后此方法被标记为过时,替换为:Constructor调用newInstance()


获取运行时类的内部结构:所有属性、所有方法、所有构造器
  • getFields():获取到运行时类本身及其所有父类中声明为public权限的属性

  • getDeclaredFields():获取当前运行时类中声明的所有属性

  • getMethods():获取到运行时类本身及其所有父类中声明为public权限的方法

  • getDeclaredMethods():获取当前运行时类中声明的所有方法


获取运行时类的内部结构:父类、接口们、包、带泛型的父类、父类的泛型等
  • getSuperclass():获取运行时类的父类
  • getInterfaces():获取运行时类的接口,因接口数量不唯一,需用数组接收,循环遍历
  • getPackage():获取运行时类的包
  • getGennericSuperclass():获取运行时类的带泛型的父类
  • 获取运行时类的父类的泛型:此代码为工具代码,用时粘贴就行
//获取当前运行时类clazz
Class<?> clazz = Class.forName("Person");
//获取运行时类的带泛型的父类
Type genericSuperclass = clazz.getGenericSuperclass();
//Class实现的接口Type可强转为ParameterizedType
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
//使用getActualTypeArguments()返回一个数组,返回所有泛型操作的名称
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
    System.out.println(actualTypeArgument);//遍历输出所有泛型父类的名称
}

调用指定的属性*

先指定一个Person类,类中要有一个空参public构造器,方便newInstance()方法生成Person的对象per``

public class Person {
    private String name;//私有属性name
    public int age;//私有属性age
    
    private Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    //空参构造器
    public Person() {
        System.out.println("person()");
    }
	//私有方法show
    private void show(int age, String name){
        System.out.println("这是show方法");
        System.out.println(age + name);
    }
}

关于属性的调用:get/set方法

import org.junit.Test;

import java.lang.reflect.Field;

public class reflectTest {
    @Test
    public void test() throws Exception {
        Class<Person> clazz = Person.class;//构建Class实例Clazz
        Person per = clazz.newInstance();//通过Clazz对象调用方法构建Person对象per
        //以下代码是获取公有属性
        Field field = clazz.getField("age");//通过getField方法获取到public属性
        field.setInt(per,18);//设置对象per的属性age为18
        System.out.println(field.get(per));
        //以下代码是获取私有属性
        Field field1 = clazz.getDeclaredField("name");//通过getDeclaredFiled方法获取到private属性
        field1.setAccessible(true);//设置私有属性可访问为true
        field1.set(per,"XIAOBAI");//给per对象的name属性设置为XIOABAI
        System.out.println(field1.get(per));
    }
}

关于方法的调用:invoke方法

@Test
public void test1() throws Exception {
    Class<Person> clazz = Person.class;//构建Class实例Clazz
    Person per = clazz.newInstance();//通过Clazz对象调用方法构建Person对象per
    //以下代码是获取私有方法
    Method method = clazz.getDeclaredMethod("show", int.class, String.class);//通过clazz对象调用方法获取show方法,在这里要写实参类型.class
    method.setAccessible(true);//设置私有方法可访问为true
    Object invoke = method.invoke(per, 22,"Xiaobai");//用per对象来调用方法,写入实参
}

注:invoke方法的返回值即为调用方法的返回值,如果是void方法则会返回null


调用静态属性的时候,不需要对象per去调用,使用Clazz实例clazz或Person.class(指代此类)去调用即可

//设name属性为私有静态属性
public void test() throws Exception {
    Class<Person> clazz = Person.class;//构建Class实例Clazz
    //以下代码是获取静态私有属性
    Field field1 = clazz.getDeclaredField("name");//通过getDeclaredFiled方法获取到private属性
    field1.setAccessible(true);//设置私有属性可访问为true
    field1.set(Person.class,"XIAOBAI");//给Person.class静态对象的name属性设置为XIAOBAI
    System.out.println(field1.get(Person.class));

调用静态属性的时候,不需要对象per去调用,使用Clazz实例clazz或Person.class(指代此类)或null去调用即可

//设show方法为私有静态方法
@Test
public void test1() throws Exception {
    Class<Person> clazz = Person.class;//构建Class实例Clazz
    Person per = clazz.newInstance();//通过Clazz对象调用方法构建Person对象per
    //以下代码是获取私有方法
    Method method = clazz.getDeclaredMethod("show", int.class, String.class);//通过clazz对象调用方法获取show方法,在这里要写实参类型.class
    method.setAccessible(true);//设置私有方法可访问为true
    Object invoke = method.invoke(null, 22,"Xiaobai");//null或clazz来调用方法,写入实参
}

调用构造器,和调用方法的区别是不需要写入方法名

@Test
public void test2() throws Exception {
    Class<Person> clazz = Person.class;
    //通过getDeclaredConstructor方法返回一个构造器,写入形参 
    Constructor<Person> constructor = clazz.getDeclaredConstructor(String.class, int.class);
    constructor.setAccessible(true);
    //使用newInstance方法生成一个对象,并写入构造器实参
    Person per = constructor.newInstance("XIAOBAI", 18);
}

对比通过Class实例调用newInstance()方法,使用Constructor调用newInstance()创建实例的方法,因为constructor.setAccessible(true);语句的原因,所以不要求构造器public,因为后面也可以写入形参,所以不要求构造器空参