反射
反射(Reflection)
- 反射就是:加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)。
如何获取某个类的信息?
-
加载类,获取类的字节码:Class对象
获取Class对象的三种方式:
- Class c1 = 类名.class
- 调用Class提供的方法:public static Class forName(String package);
- Object提供的方法:public Class getClass; Class c3 = 对象.getClass();
-
获取类的构造器:Construtor对象
-
方法 说明 Constructor<?>[] getConstructors() 获取全部构造器(只能获取public修饰的) Constructor<?>[] getDeclaredConstructors() 获取全部构造器(只要存在就能拿到) Constructor getConstructor(Class<?>… parameterTypes) 获取某个构造器(只能获取public修饰的) Constructor getDeclaredConstructor(Class<?>… parameterTypes) 获取某个构造器(只要存在就能拿到) 获取类构造器的作用:初始化对象并返回
Construtor提供的方法 说明 T newInstance(Object… initargs) 调用次构造器对象表示的构造器,并传入参数,完成对象的初始化并返回 public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)
-
-
获取类的成员变量:Field对象
-
方法 说明 public Field[] getFields() 获取类的全部成员变量(只能获取public修饰的) public Field[] getDeclaredFields() 获取类的全部成员变量(只要存在就能拿到) public Field getField(String name) 获取类的某个成员变量(只能获取public 修饰的) public Field getDeclaredField(String name) 获取类的某个成员变量(只要存在就能拿到) 对获取到的成员变量进行赋值和取值
方法 说明 void set(Object obj,Object value) 赋值 Object get(Object obj) 取值 public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)
-
-
获取类的成员方法:Methond对象
-
方法 说明 Method[] getMethods() 获取类的全部成员方法(只能获取public修饰的) Method[] getDeclaredMethods() 获取类的全部成员方法(只要存在就能拿到) Method getMethod(String name,Class<?>… parameterTypes) 获取类的的某个成员方法(只能获取public修饰的) Method getDeclaredMethod(String name,Class<?>… paraterTypes) 获取类的某个成员方法(只要存在就能拿到) 执行成员方法
Method提供的方法 说明 public Object invoke(Object obj,Object… args) 触发某个对象的该方法执行 public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射) 示例代码:
package reflect; public class Student { public int age; private String name; public Student() { System.out.println("无参数构造器"); } public Student(int age) { this.age = age; System.out.println("public 有参数构造器"); } private Student(String name) { this.name = name; System.out.println("private 有参数构造器"); } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void study(){ System.out.println("我爱学习"); } public void study(String name){ System.out.println(name + "爱学习"); } private void play(){ System.out.println("我爱打游戏"); } }
package reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class TestClass { public static void main(String[] args) throws Exception { System.out.println("--------获取类的字节码文件--------------"); //方式一 Class c1 = Student.class; System.out.println(c1.getName()); //全类名 System.out.println(c1.getSimpleName());//简名 Student //方式二 Class c2 = Class.forName("reflect.Student"); //参数是全限定名 System.out.println(c2.getName()); //方式三 Student s1 = new Student(); Class c3 = s1.getClass(); //三种方式取得的都是同一个Class对象 System.out.println(c1 == c2); System.out.println(c1 == c3); System.out.println("-------------------获取类的构造器------------------------"); //只能获取public所有的构造器 Constructor[] constructors = c1.getConstructors(); for (int i = 0; i < constructors.length; i++) { System.out.println(constructors[i].getName() + " --->" + constructors[i].getParameterCount()); } //可以获取所有的构造器 Constructor[] constructors2 = c1.getDeclaredConstructors(); for (int i = 0; i < constructors2.length; i++) { System.out.println(constructors2[i].getName() + " --->" + constructors2[i].getParameterCount()); } //获取某个public 构造器 Constructor constructors3 = c1.getConstructor(); System.out.println(constructors3.getName() + " --->" + constructors3.getParameterCount()); //获取某个任意一个有参数的构造器,参数就是构造器的参数类型.class Constructor constructors4 = c1.getDeclaredConstructor(String.class); System.out.println(constructors4.getName() + " --->" + constructors4.getParameterCount()); System.out.println("----------------使用构造器初始化对象并返回-----------------------"); //禁止访问检查,即使是private构造器,在外面也可以调用 constructors4.setAccessible(true); Student s = (Student) constructors4.newInstance("zxx"); System.out.println("-------------------获取类的成员变量------------------"); Field[] field = c1.getFields(); for (int i = 0; i < field.length; i++) { System.out.println(field[i].getName() + " " + field[i].getType()); } Field[] field2 = c1.getDeclaredFields(); for (int i = 0; i < field2.length; i++) { System.out.println(field2[i].getName() + " " + field2[i].getType()); } Field fage = c1.getField("age"); System.out.println(fage.getName() + " " + fage.getType()); Field fname = c1.getDeclaredField("name"); System.out.println(fname.getName() + " " + fname.getType()); System.out.println("------------------------对成员变量进行赋值和取值--------------------------------"); Student student = new Student(); //对某个对象进行赋值 fage.set(student, 5); //对某个对象进行取值 System.out.println(fage.get(student)); System.out.println("----------------------从类中获取成员方法-----------------------------------------"); Method[] methods = c1.getMethods(); for (Method method : methods) { System.out.println(method.getName() + "--" + method.getParameterCount() + "--" + method.getParameterTypes()); } System.out.println("--------------------"); Method[] methods2 = c1.getDeclaredMethods(); for (Method method : methods2) { System.out.println(method.getName() + "--" + method.getParameterCount() + "--" + method.getParameterTypes()); } //无参 Method m1 = c1.getMethod("study"); System.out.println(m1.getName()); //有参 Method m2 = c1.getMethod("study", String.class); System.out.println(m2.getName()); //私有方法 Method m3 = c1.getDeclaredMethod("play"); System.out.println(m3.getName()); System.out.println("---------------------------------调用类中的成员方法----------------------------------------"); // 无参的study方法,无返回值res = null Object res = m1.invoke(student); // 有参的study方法 m2.invoke(student, "zxx"); // private方法 m3.setAccessible(true); m3.invoke(student); } }
-
反射的作用和应用场景
- 基本作用:可以得到一个类中的全部成分然后进行操作
- 可以破坏封装性
- 适合做Java的框架
使用反射做一个简易版的框架
需求:对于任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去
实现步骤:
- 定义一个方法,可以接受任意对象
- 每收到一个对象后,使用反射获取该对象的Class对象,然后获取全部的成员信息
- 遍历成员列表,然后提取成员变量在该对象中的具体值
- 把成员变量名、对应的值,写到文件中去
package reflect;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
public class SimpleFrame {
public static void getFieldsAndValue(Object obj) throws IllegalAccessException, FileNotFoundException {
PrintStream printStream = new PrintStream(new FileOutputStream(new File("D:\\javaCode\\ReflectStudy\\src\\demo.txt")), true);
// obj是任意对象
Class c1 = obj.getClass();
String cname = c1.getName();
printStream.println("---------------" + cname + "-------------------");
// 2.从这个类中获取全部成员变量
Field[] fields = c1.getDeclaredFields();
// 3.遍历成员变量
for (Field field : fields) {
// 4.拿到成员变量的名字
String fieldName = field.getName();
field.setAccessible(true);
String fieldValue = field.get(obj) + "";
printStream.println(fieldName + "->" + fieldValue);
}
printStream.close();
}
}