Java 反射
一. 概述
反射:加载类,并允许以编程的方式解剖类中的各个成分(成员变量、方法、构造器等等)
二. 获取类的字节码:Class对象
三种方式:
1. Class c1 = 类名.class:
2. 调用Class提供的方法:public static Class forName(String package)
3. Object提供的方法:public Class getClass(); Calss3 = 对象.getClass()
public class Student {
    private String name;
    private int age;
    public Student() {
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
public static void main(String[] args) throws ClassNotFoundException {
        Class c = Student.class;
        System.out.println(c.getName());//全类名
        System.out.println(c.getSimpleName());//简名 Student
        Class c2 = Class.forName( "com.wyyzs.d01.Student");
        System.out.println(c2.getName());
        System.out.println(c2.getSimpleName());
        Student student = new Student();
        Class c3 = student.getClass();
        System.out.println(c3.getName());
        System.out.println(c3.getSimpleName());
}三. 获取类的构造器
获取类的构造器
| Class提供了从类中获取构造器的方法 | 说明 | 
| Constructor<?>[] getConstructors() | 获取全部构造器(只能获取public 修饰的) | 
| Constructor<?>[] getDeclaredConstructors() | 获取全部构造器(只要存在就能拿到) | 
| Constructor<?>[] getConstructor (Class<?>... parameterTypes) | 获取某个构造器(只能获取public修饰的) | 
| Constructor<?>[] getDeclaredConstructor(Class<?>... parameterTypes) | 获取某个构造器(只要存在就能拿到) | 
获取类构造器的作用
初始化对象返回
| Constructor提供的方法 | 说明 | 
| T newInstance(Object... initargs) | 调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回 | 
| public void setAccessible(boolean flag) | 设置true,表示禁止检查访问控制(暴力反射) | 
public class Student {
    private String name;
    private int age;
    public Student() {
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    private Student(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
@Test
    public void test1() throws Exception {
        Class studentClass = Student.class;
        //Constructor<?>[] getConstructors()	获取全部构造器(只能获取public 修饰的)
        Constructor[] constructors = studentClass.getConstructors();
        for(Constructor constructor : constructors){
            System.out.println(constructor.getName() + " " + constructor.getParameterTypes().length);
        }
        System.out.println("------------------------");
        //Constructor<?>[] getDeclaredConstructors()	获取全部构造器(只要存在就能拿到)
        Constructor[] constructors2 = studentClass.getDeclaredConstructors();
        for(Constructor constructor : constructors2){
            System.out.println(constructor.getName() + " " + constructor.getParameterTypes().length);
        }
        System.out.println("------------------------");
        //Constructor<?>[] getConstructor(Class<?>... parameterTypes) 	获取某个构造器(只能获取public修饰的)
        //无参
        Constructor constructors3 = studentClass.getConstructor();
        System.out.println(constructors3.getName() + " " + constructors3.getParameterTypes().length);
        //有参
        Constructor constructors4 = studentClass.getConstructor(String.class, int.class);
        System.out.println(constructors4.getName() + " " + constructors4.getParameterTypes().length);
        System.out.println("------------------------");
        //Constructor<?>[] getDeclaredConstructor(Class<?>... parameterTypes)	获取某个构造器(只要存在就能拿到)
        //无参
        Constructor constructors5 = studentClass.getDeclaredConstructor();
        System.out.println(constructors5.getName() + " " + constructors5.getParameterTypes().length);
        //有参
        Constructor constructors6 = studentClass.getDeclaredConstructor(String.class);
        System.out.println(constructors6.getName() + " " + constructors6.getParameterTypes().length);
        Constructor constructors7 = studentClass.getDeclaredConstructor(String.class, int.class);
        System.out.println(constructors7.getName() + " " + constructors7.getParameterTypes().length);
        //T newInstance(Object... initargs)	调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回
        //public void setAccessible(boolean flag)	设置true,表示禁止检查访问控制(暴力反射)
        //调 constructors6 私有构造器 会报权限异常 此时 使用 setAccessible 设置true,表示禁止检查访问控制(暴力反射)
       /* Student student = (Student) constructors6.newInstance();
        System.out.println(student);*/
        constructors6.setAccessible(true);
        Student student2 = (Student) constructors6.newInstance("卡莎");
        System.out.println(student2);
       Student student3 = (Student) constructors7.newInstance("卡莎", 18);
        System.out.println(student3);
    }四. 获取类的成员变量
从类中获取成员变量的方法
| Class提供了从类中获取成员变量的方法 | 说明 | 
| 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) | 设置为ture,表示禁止检查访问控制 | 
public class Dog {
    private String name;
    private int age;
    public static int o;
    public static  final String C = "狗狗";
    public Dog() {
    }
    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
 @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
 @Test
   public void Test3_Field() throws NoSuchFieldException {
        //获取类的成员变量
        //得到类的Class对象
        Class dog = Dog.class;
        //public Field[] getFields()	获取类全部的成员变量(只能获取public修饰的)
        Field[] fields = dog.getFields();
        for(Field f : fields){
            System.out.println(f.getName() + "---->" + f.getType());
        }
        System.out.println("-------------------------------------");
        //public Field[] getDeclaredFields()	获取类的全部成员变量(只要存在就能拿到)
        Field[] fields1 = dog.getDeclaredFields();
        for(Field f : fields1){
            System.out.println(f.getName() + "---->" + f.getType());
        }
        System.out.println("-------------------------------------");
        //public Field getField(String name)	获取类的某个成员变量(只能获取public修饰的)
        Field field = dog.getField("o");
        System.out.println(field.getName() + "---->" + field.getType());
        Field field2 = dog.getField("C");
        System.out.println(field2.getName() + "---->" + field2.getType());
        System.out.println("-------------------------------------");
        //public Field getDeclaredField(String name)	获取类的某个成员变量(只要存在就能获取)
        Field field3 = dog.getDeclaredField("name");
        System.out.println(field3.getName() + "---->" + field3.getType());
        Field field4 = dog.getDeclaredField("age");
        System.out.println(field4.getName() + "---->" + field4.getType());
        System.out.println("===================================");
        //void set(Object obj, Object value)	赋值
        Dog dog1 = new Dog();
        //field3->name 为私有 赋值会抛异常 需要 void setAccessible(boolean flag) 设置为ture,表示禁止检查访问控制
        //public void setAccessible(boolean flag)	设置为ture,表示禁止检查访问控制
        field3.setAccessible(true);
        field3.set(dog1, "拉布拉多");
        System.out.println(dog1);
        //Object get(Object obj)	取值
        //field3->name
        String name = (String) field3.get(dog1);
        System.out.println(name);
    }五. 获取类的成员方法
从类中获取成员方法
| Class提供了从类中获取成员方法 | 说明 | 
| Method[] getMethods() | 获取类的全部成员方法(只能获取public 修饰的) 使用较少 | 
| Method[] getDeclaredMethods() | 获取类的全部成员方法(只要存在就能拿到) | 
| Method getMethod(String name, Class<?> parameterTypes) | 获取类的某个成员方法(只能获取public修饰的) | 
| Method getDeclaredMethod(String name, Class<?> parameterTypes) | 获取类的某个成员方法(只要存在就能拿到) | 
获取成员方法的作用
获取成员方法的作用是执行该方法
| Method提供的方法 | 说明 | 
| public Object invoke(Object obj, Object... args) | 执行某个对象的该方法 | 
| public void setAccessible(boolean flag) | 设置为ture,表示禁止检查访问控制 | 
public class Dog {
    private String name;
    private int age;
    public static int o;
    public static  final String C = "狗狗";
    public Dog() {
    }
    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String eat(String food) {
        return "吃" + food + "吃的贼多";
    }
    public void run() {
        System.out.println("跑的贼快");
    }
    private void sleep() {
        System.out.println("睡得贼香");
    }
}
 @Test
    public void testGetMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class d = Dog.class;
        //Method[] getMethods()	获取类的全部成员方法(只能获取public 修饰的) 使用较少
        Method[] methods = d.getMethods();
        for(Method m : methods){
            System.out.println(m.getName() + "-->" + m.getParameterTypes().length);
        }
        System.out.println("-------------------");
        //Method[] getDeclaredMethods()	获取类的全部成员方法(只要存在就能拿到)
        Method[] methods2 = d.getDeclaredMethods();
        for(Method m : methods2){
            System.out.println(m.getName() + "-->" + m.getParameterTypes().length);
        }
        System.out.println("-------------------");
        //Method getMethod(String name, Class<?> parameterTypes)	获取类的某个成员方法(只能获取public修饰的)
        Method method = d.getMethod("eat", String.class);
        System.out.println(method.getName() + "-->" + method.getReturnType());
        //Method getDeclaredMethod(String name, Class<?> parameterTypes)	获取类的某个成员方法(只要存在就能拿到)
        Method method2 = d.getDeclaredMethod("sleep");
        System.out.println(method2.getName() + "-->" + method2.getReturnType());
        System.out.println("====================");
        //public Object invoke(Object obj, Object... args)	执行某个对象的该方法
        Dog dog = new Dog();
        //method为 public 可直接调用
        String s = (String) method.invoke(dog, "王中王");
        System.out.println(s);
        //method2->sleep为private 直接执行会报错 需要 void setAccessible(boolean flag)	设置为ture,表示禁止检查访问控制
        //public void setAccessible(boolean flag)	设置为ture,表示禁止检查访问控制
        method2.setAccessible(true);
        method2.invoke(dog);
    }六. 反射的作用、应用场景
作用
1. 基本作用:可以得到一个类的全部成分然后进行操作。
2. 可以破坏封装性
3. 最重要的用途:适合做Java框架,主流的框架都会基于反射设计出一些通用的功能
简易版框架
实现步骤:
1. 定义一个方法,可以接收任意对象
2. 没收到一个对象后,使用反射获取该对象的Class对象,然后获取全部的成员变量
3. 变量成员变量,然后提取成员变量在该对象中的具体值
4. 把成员变量名和值写到文件中
public class Student {
    private String name;
    private int age;
    private String gender;
    private String grade;
    public Student() {
    }
    public Student(String name, int age, String gender, String grade) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.grade = grade;
    }
}
public class Teacher {
    private String name;
    private int age;
    private String subject;
    public Teacher() {
    }
    public Teacher(String name, int age, String subject) {
        this.name = name;
        this.age = age;
        this.subject = subject;
    }
}
 @Test
    public void testA() throws Exception {
        Student s1 = new Student("卡莎", 18, "女", "99.8");
        Teacher teacher = new Teacher("张飞", 25, "语文");
        ObjectFrame.saveObject(s1);
        ObjectFrame.saveObject(teacher);
    }