1.概述
反射就是通过对象的字节码生成对应的对象及对象的各个成员。一个类的成员包括:包名package,构造器constructor,属性字段field,普通方法method. 因此类的字节码同样是由这四样构成,反射的目的也是获取这四个成员。
2.获取字节码的三种方式
① :类.Class;
② 对象.getClass();
③ Class.forName(“类的全路径”);
以Student为例子:
package com.example.demo.reflect1.study;
@Data
public class Student {
private String name;
public int age;
private double score;
public Student() {}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void helloWorld() {
System.out.println("hello world!");
}
public void hiGirl(String name) {
System.out.println("good night:" + name + "!");
}
}
获取字节码的三种方式:
①:Class class1 = Student.class;
②:Student student = new Student();Class class2 = student.getClass();
③:Class class3 = Class.forName("com.example.demo.reflect1.study.Student");
3.通过反射生成对象
1.获取构造器
创建一个类是通过构造方法来创建,因此需要先获取字节码中的构造器。获取构造器的方法:
1.获取有(无)参数的构造器:class.getConstructor(Class<?>… parameterType);
2.获取一个类的所有构造器:class.getConstructors();
栗子:
获取所有构造器:Constructor[] constructor3 = class3.getConstructors();
获取构造器(无参数)–Student(){}构造函数也没有参数:Constructor constructor1 = class3.getConstructor();
获取构造器(有参数),从Student(String name, int age) {} 的构造函数可以看出参数为String.class和int.class.:
Constructor constructor2 = class3.getConstructor(String.class,int.class);
2.通过构造器创建对象
通过调用newInstance()方法生成实例对象。
Student student1 = (Student) constructor1.newInstance();
Student student2 = (Student) constructor2.newInstance("xie",25);
3.总结
整体流程就是:获取类的字节码–>通过字节码获取构造器–>通过构造器调用newInstance()生成实例对象.
4.通过反射获取对象的成员变量
通过字节码获取成员属性信息,包括修饰符,类型,名称,值。以 Class studentClass = Class.forName("com.example.demo.reflect1.study.Student");
为例子。
1.获取属性字段信息
1.获取所有的属性字段:Field[] fields = studentClass.getDeclaredFields();
2.获取属性为age的字段:Field field = studentClass.getDeclaredField("age");
2.获取属性所在类的全路径
获取属性字段所在类的全路径:String classPath = field.getDeclaringClass().getTypeName();
3.获取修饰符
int mod = field.getModifiers();
修饰符:0.默认,1.public,2.private,4.protected
4.获取字段类型
Class type = field.getType();
字段类型:int、double、String等。
5.获取字段名
String fieldName = field.getName();
6.获取字段的值
当修饰符为private的时候不能直接获取,需要添加fieldAge.setAccessible(true);
否则会显示权限不足。
Student student = (Student) studentClass.newInstance();
Object value =field.get(student);
System.out.println("age字段值:"+value);
Field fieldAge = studentClass.getDeclaredField("name");
//私有属性字段需添加:fieldAge.setAccessible(true);
Object valueName =fieldAge.get(student);
System.out.println("nmae字段值:"+valueName);
7.结果
上面的输出结果为:
类的全路径:com.example.demo.reflect1.study.Student
权限类型:1
字段名:age
数据类型:int
age字段值:20
name字段值:null
5.通过反射调用方法
通过反射调用类里面的成员方法:
Class studentClass = Student.class;
Student student = (Student) studentClass.getConstructor().newInstance();
1.获取类里面的所有方法
Methods[] methods = studentClass.getMethods();
它获取的方法还包括它父类的所有方法,比如在这里它不仅包括Student中的helloWorld()和hiGirl(String Name),还包括Object的8个方法即toString(),equal,notify()等;
2.获取和调用某个方法
1.获取某个方法:
Method method =studentClass.getMethod("方法名",方法的参数对应的类型...);
2.调用某个方法:
method.invoke(方法所在的对象实例,方法参数...);
比如,获取并调用student的helloWorld()方法:
Method method1 = studentClass.getMethod("helloWorld");
method1.invoke(student);
获取并调用student的hiGirl(String name)方法:
Method method2 = studentClass.getMethod("hiGirl",String.class);
method2.invoke(student,"y");
3.结果:
hello world!
good night:y!