反射-反射的应用
反射的应用
注: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,因为后面也可以写入形参,所以不要求构造器空参