Java反射
一、获取class对象
1.1 Studnet类
package reflection;
public class Student {
private String name;
private int age;
}
1.2 获取class对象有三种方式
- Class.forName(“全类名”)
- 类名.class
- 对象.class
package reflection;
public class ClassTest {
public static void main(String[] args) throws ClassNotFoundException {
// 1.Class.forName("全类名")
// 经常使用,很多实现都是用这种,idea各种代码提示
Class class1 = Class.forName("reflection.Student");
// 2.类名.class
// 一般当参数时使用 例如:synchronized (Student.class) {}
Class class2 = Student.class;
// 3.对象.class
// 很少用
Class class3 = new Student().getClass();
// 三种获取方法都是同样的
System.out.println(class1 == class2); // true
System.out.println(class3 == class2); // true
}
}
二、反射获取构造方法
2.1 Studnet类
package reflection;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
protected Student(int age) {
this.age = age;
}
private Student(String name) {
this.name = name;
}
}
2.2 通过反射获取构造方法的方式
- 获取所有公有的构造方法
Constructor<?>[] getConstructors()
- 获取所有的构造方法
Constructor<?>[] getDeclaredConstructors()
- 按参数获取单个公有的构造方法
Constructor<?> getConstructor()
- 按参数获取单个任意权限构造方法
Constructor<?> getDeclaredConstructor()
package reflection;
import java.lang.reflect.Constructor;
import java.util.Arrays;
public class ConstructorTest {
public static void main(String[] args) throws Exception {
Class<Student> clazz = Student.class;
// 1.获取**所有公有**的构造方法
Constructor<?>[] cons1 = clazz.getConstructors();
for (Constructor<?> constructor : cons1) {
System.out.println(constructor);
}
/*
输出:
public reflection.Student(java.lang.String,int)
public reflection.Student()
*/
// 2.获取**所有**的构造方法
Constructor<?>[] cons2 = clazz.getDeclaredConstructors();
for (Constructor<?> constructor : cons2) {
System.out.println(constructor);
}
/*
输出:
private reflection.Student(java.lang.String)
protected reflection.Student(int)
public reflection.Student(java.lang.String,int)
public reflection.Student()
*/
// 3.参数获取**单个任意权限**构造方法
Constructor<Student> cons3 = clazz.getDeclaredConstructor();
System.out.println(cons3); // public reflection.Student()
Constructor<Student> cons4 = clazz.getDeclaredConstructor(int.class);
System.out.println(cons4); // protected reflection.Student(int)
Constructor<Student> cons5 = clazz.getDeclaredConstructor(String.class);
System.out.println(cons5); // private reflection.Student(java.lang.String)
Constructor<Student> cons6 = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(cons6); // public reflection.Student(java.lang.String,int)
// 4.按参数获取**单个公有**的构造方法
// clazz.getConstructor()
// 和3基本相同 略...
}
}
2.3 Constructor构造方法对象的应用
- 暂时跳过权限校验 ``void setAccessible()`
- 调用构造方法
T newInstance()
package reflection;
import java.lang.reflect.Constructor;
import java.util.Arrays;
public class ConstructorTest {
public static void main(String[] args) throws Exception {
Class<Student> clazz = Student.class;
// 通过构造方法对象cons获取方法参数
Constructor<Student> cons = clazz.getDeclaredConstructor(String.class);
System.out.println(Arrays.toString(cons.getParameters())); // [java.lang.String arg0]
// 这个方法是private修饰的,可以通过setAccessible(true),强制跳过权限校验
System.out.println(cons); // private reflection.Student(java.lang.String)
// 暴力反射
cons.setAccessible(true);
cons.newInstance("name");
}
}
2.4 获取构造方法的修饰符
- 获取修饰符
int getModifiers()
package reflection;
import java.lang.reflect.Constructor;
import java.util.Arrays;
public class ConstructorTest {
public static void main(String[] args) throws Exception {
Class<Student> clazz = Student.class;
System.out.println(cons.getModifiers()); // 2
}
}
利用二进制位来表示是否有对应的修饰符:
三、反射获取成员变量
3.1 Studnet类
package reflection;
public class Student {
private String name;
public int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
获取的方式和构造方法基本一样,Constructor 和 Field 的区别
3.2 通过反射获取成员变量的方式
- 获取所有公有的成员变量
Field[] getFields()
- 获取所有的成员变量
Field[] getDeclaredFields()
- 获取单个公有的成员变量
Field getField(变量名)
- 获取单个任意权限的成员变量
Field getDeclaredField(变量名)
package reflection;
import java.lang.reflect.Field;
import java.util.Arrays;
public interface FieldsTest {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("reflection.Student");
// 1.获取**所有公有**的成员变量 `Field[] getFields()`
Field[] field1 = clazz.getFields();
System.out.println(Arrays.toString(field1)); // [public int reflection.Student.age]
// 2.获取**所有**的成员变量 `Field[] getDeclaredFields()`
Field[] fields2 = clazz.getDeclaredFields();
System.out.println(Arrays.toString(fields2));
// 输出:
// [private java.lang.String reflection.Student.name, public int reflection.Student.age]
// 3.获取单个公有的成员变量 `Field[] getField(变量名)`
Field fields3 = clazz.getField("age");
System.out.println(fields3); // public int reflection.Student.age
// 4.获取**单个任意权限**的成员变量 `Field[] getDeclaredField(变量名)`
Field fields4 = clazz.getDeclaredField("name");
System.out.println(fields4); // private java.lang.String reflection.Student.name
// 1.获取修饰符,和上述构造方法一样
System.out.println(fields4.getModifiers()); // 2
// 2.获取变量名
System.out.println(fields4.getName()); // name
// 3.通过反射对一个对象的变量进行操作
Student stu = new Student("lisi", 28);
fields4.setAccessible(true); // 暂时跳过权限校验
// 3.1尽管没有get方法,且还是private的也可以获取到
System.out.println(fields4.get(stu)); // lisi
// 3.2尽管没有set方法,且还是private的也可以设置
fields4.set(stu, "zhangsan");
System.out.println(stu); // Student{name='zhangsan', age=28}
}
}
3.3 Field成员变量对象的应用
- 获取修饰符
int getModifiers()
- 获取变量名
String getName()
- 暂时跳过权限校验 ``void setAccessible()`
- 获取对象的值
Object get()
- 设置对象的值
void set()
package reflection;
import java.lang.reflect.Field;
import java.util.Arrays;
public interface FieldsTest {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("reflection.Student");
// 获取私有成员变量name
Field field = clazz.getDeclaredField("name");
// 1.获取修饰符,和上述构造方法一样
System.out.println(field.getModifiers()); // 2
// 2.获取变量名
System.out.println(field.getName()); // name
// 3.通过反射对一个对象的变量进行操作
Student stu = new Student("lisi", 28);
field.setAccessible(true); // 暂时跳过权限校验
// 3.1尽管没有get方法,且还是private的也可以获取到
System.out.println(field.get(stu)); // lisi
// 3.2尽管没有set方法,且还是private的也可以设置
field.set(stu, "zhangsan");
System.out.println(stu); // Student{name='zhangsan', age=28}
}
}
三、反射获取成员方法
4.1 Studnet类
package reflection;
public class Student {
private String name;
public int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
获取的方式和构造方法和成员变量一样,Constructor 、Field 和 Method 的区别
4.2 通过反射获取成员方法的方式
- 获取所有公有的成员方法(包括父类的公有方法)
Method[] getMethods()
- 获取所有的成员方法(不包括父类的方法)
Method[] getMethodFields()
- 获取单个公有的成员方法 (包括父类的公有方法)
Method getMethod()
- 获取单个任意权限的成员方法(不包括父类的方法)
Method getDeclaredMethod()
package reflection;
import java.lang.reflect.Method;
import java.util.Arrays;
public class MethodTest {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("reflection.Student");
// 1.获取**所有公有**的成员方法(**包括父类的公有方法**)`Method[] getMethods()`
Method[] method1 = clazz.getMethods();
System.out.println(Arrays.toString(method1));
System.out.println("====================");
// 2.获取**所有**的成员方法(**不包括父类的方法**)`Method[] getMethodFields()`
Method[] method2 = clazz.getDeclaredMethods();
System.out.println(Arrays.toString(method2));
System.out.println("====================");
// 3.获取**单个公有**的成员方法 (**包括父类的公有方法**)`Method[] getMethod()`
Method method3 = clazz.getMethod("eat", String.class, int.class);
System.out.println(method3);
System.out.println("====================");
// 4.获取**单个任意权限**的成员方法(**不包括父类的方法**)`Method[] getDeclaredMethod()`
Method method4 = clazz.getDeclaredMethod("eat", String.class);
System.out.println(method4);
}
}
程序运行结果:
·
4.3 Method成员方法对象的应用
- 获取修饰符
int getModifiers()
- 获取变量名
String getName()
- 暂时跳过权限校验
void setAccessible()
- 获取方法参数
Parameter[] getParameters()
- 获取方法抛出的异常
Class<?>[] getExceptionTypes()
- 调用该方法
Object invoke()
package reflection;
import java.lang.reflect.Method;
import java.util.Arrays;
public class MethodTest {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("reflection.Student");
// 获取私有方法eat()
Method method = clazz.getDeclaredMethod("eat", String.class);
// 1.获取修饰符 `int getModifiers()`
System.out.println(method.getModifiers()); // 2
System.out.println("====================");
// 2.获取变量名`String getName()`
System.out.println(method.getName()); // eat
System.out.println("====================");
// 3.获取方法参数 `Parameter[] getParameters()`
System.out.println(Arrays.toString(method.getParameters())); // [java.lang.String arg0]
System.out.println("====================");
// 4.获取方法抛出的异常 `Class<?>[] getExceptionTypes()`
System.out.println(Arrays.toString(method.getExceptionTypes()));
// 输出:
// [class java.io.IOException, class java.lang.RuntimeException]
System.out.println("====================");
// 5.调用该方法 `Object invoke()`
method.setAccessible(true); // 暂时跳过权限校验
Object result = method.invoke(new Student(), "苹果"); // 在吃:苹果
System.out.println(result); // ok
}
}
四、利用反射保存任意对象信息
想想如果不用反射的话,还需要利用get()方法一个个调用,并且最根本的是无法判断该对象的属性到底有哪些。
利用反射中getDeclaredFields()
操作即可对变量为所欲为!!!暴力!
package reflection;
import java.lang.reflect.Field;
public class SaveTest {
public static void main(String[] args) throws IllegalAccessException {
Student stu = new Student("Lisi", 18);
Teacher tch = new Teacher("LaoWang", 9999);
save(stu);
System.out.println("===============");
save(tch);
}
/**
* 保存任意对象的信息
* @param obj
* @throws IllegalAccessException
*/
public static void save(Object obj) throws IllegalAccessException {
// 1.通过对象获取到类的字节码文件
Class<?> clazz = obj.getClass();
// 2.调用getDeclaredFields()方法获取所以成员变量
for (Field field : clazz.getDeclaredFields()) {
// 3.跳过权限,可能为private
field.setAccessible(true);
// 4.获取变量名
String name = field.getName();
// 4.获取变量对应的值
Object value = field.get(obj);
System.out.println(name + " : " + value);
// 5.保存到文件... ,略
}
}
}
输出结果: