109-Java反射:概述、获取Class类对象、获取Constructor、Field、Method对象、反射作用:绕过编译阶段做企业级框架

反射

1、概述
  • 反射是指对于任何一个Class类,在 “运行的时候” 都可以直接得到这个类的全部成分。
  • 在运行时:
    • 可以直接得到这个类的构造器对象:Constructor
    • 可以直接得到这个类的成员变量对象:Field
    • 可以直接得到这个类的成员方法对象:Method
  • 这种运行时动态获取类信息自己动态调用类中成分的能力称为:Java语言的反射机制

(1)反射的关键
  • 反射的第一步都是先得到编译后的Class类对象,然后就可以得到Class的全部成分。

    109-Java反射:概述、获取Class类对象、获取Constructor、Field、Method对象、反射作用:绕过编译阶段做企业级框架_第1张图片


总结
  1. 反射的基本作用、关键?
    • 反射是在运行时获取类的字节码文件对象:然后可以解析类中的全部成分
    • 反射的核心思想和关键是:得到编译以后的class文件对象


2、获取类对象
  • 反射的第一步:获取Class类的对象

    109-Java反射:概述、获取Class类对象、获取Constructor、Field、Method对象、反射作用:绕过编译阶段做企业级框架_第2张图片



(1)范例
package com.app.d2_reflect_class;

public class Student {

}
package com.app.d2_reflect_class;

/**
    目标:学习反射第一步:获取Class类的对象的方式
 */
public class Test {
    public static void main(String[] args) throws Exception {
        // 1、Class类中的一个静态方法:forName(全限名:包名 + 类名)
        Class c1 = Class.forName("com.app.d2_reflect_class.Student");
        System.out.println("c1 = " + c1);

        // 2、类名.class
        Class c2 = Student.class;
        System.out.println("c2 = " + c2);

        // 3、对象.getClass():获取对象对应类的Class对象
        Student stu = new Student();
        Class c3 = stu.getClass();
        System.out.println("c3 = " + c3);
    }
}
c1 = class com.app.d2_reflect_class.Student
c2 = class com.app.d2_reflect_class.Student
c3 = class com.app.d2_reflect_class.Student

Process finished with exit code 0


总结
  1. 反射的第一步是啥?
    • 获取Class类对象,如此才可以解析类的全部成分
  2. 获取Class类的对象的三种方式是啥?
    • 方式一:Class c1 = Class.forName(“全类名”);
    • 方式二:Class c2 = 类名.class;
    • 方式三:Class c3 = 对象.getClass();


3、获取构造器对象
  • 使用反射技术获取构造器对象并使用:

    • 反射第一步是先得到类对象,然后从类对象中获取类的成分对象。

    109-Java反射:概述、获取Class类对象、获取Constructor、Field、Method对象、反射作用:绕过编译阶段做企业级框架_第3张图片


(1)Class类中用于获取构造器的方法
方法名称 说明
Constructor< ? >[] getConstructors() 返回所有构造器对象的数组(只能拿public的)
Constructor< ? >[] getDeclaredConstructors() 返回所有构造器对象的数组,存在就能拿到
Constructor< T > getConstructor(Class< ? >… parameterTypes) 返回单个构造器对象(只能拿public的)
Constructor< T > getDeclaredConstructor(Class< ? >… parameterTypes) 返回单个构造器对象,存在就能拿到

范例
package com.app.d3_reflect_constructor;

/**
    学生类
 */
public class Student {
    private String name;
    private int age;

    public Student() {
        System.out.println("无参构造器执行");
    }

    public Student(String name, int age) {
        System.out.println("有参数构造器执行");
        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;
    }
}
package com.app.d3_reflect_constructor;

import org.junit.Test;

import java.lang.reflect.Constructor;

/**
    目标:学习使用反射技术获取构造器对象并使用
 */
public class TestStudent01 {
    // 第一步:获取类对象
    public static Class c = Student.class;

    /**
        getConstructors:
            获取所有public修饰的构造器对象(只能拿有public修饰的)
     */
    @Test
    public void getConstructors() {
        System.out.println("1. 获取所有public修饰的构造器对象:");
        // 第二步:返回所有public修饰的构造器对象的数组
        Constructor[] constructors = c.getConstructors();

        // 第三步:遍历所有public修饰的构造器对象的数组
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + " ---> " + constructor.getParameterCount());
        }

        System.out.println();
    }



    /**
        getDeclaredConstructors:
            获取所有构造器对象
     */
    @Test
    public void getDeclaredConstructors() {
        System.out.println("2. 获取所有构造器对象:");
        // 第二步:返回所有构造器对象的数组
        Constructor[] declaredConstructors = c.getDeclaredConstructors();

        // 第三步:遍历所有构造器对象的数组
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor.getName() + " ---> " + declaredConstructor.getParameterCount());
        }

        System.out.println();
    }


    /**
        getConstructor:
            获取某个有public修饰的构造器对象(只能拿public修饰的)
     */
    @Test
    public void getConstructor() throws Exception {
        System.out.println("3. 获取某个有public修饰的构造器对象:");
        // 第二步:获取某个有public修饰的无参数构造器对象
        System.out.println("获取有public修饰的无参数构造器对象:");
        Constructor constructor = c.getConstructor();
        System.out.println(constructor.getName() + " ---> " + constructor.getParameterCount());

        // 第三步:获取某个有public修饰的有参数构造器对象
        System.out.println("获取有public修饰的有参数构造器对象:");
        Constructor constructor1 = c.getConstructor(String.class, int.class);
        System.out.println(constructor1.getName() + " ---> " + constructor1.getParameterCount());

        System.out.println();
    }


    /**
        getDeclaredConstructor:
            获取某个构造器对象
     */
    @Test
    public void getDeclaredConstructor() throws Exception {
        System.out.println("4. 获取某个构造器对象:");
        // 第二步:获取无参数构造器对象
        System.out.println("获取无参数构造器对象:");
        Constructor declaredConstructor = c.getDeclaredConstructor();
        System.out.println(declaredConstructor.getName() + " ---> " + declaredConstructor.getParameterCount());

        // 第三步:获取有参数构造器对象
        System.out.println("获取有参数构造器对象:");
        Constructor declaredConstructor1 = c.getDeclaredConstructor(String.class, int.class);
        System.out.println(declaredConstructor1.getName() + " ---> " + declaredConstructor1.getParameterCount());

        System.out.println();
    }
}

109-Java反射:概述、获取Class类对象、获取Constructor、Field、Method对象、反射作用:绕过编译阶段做企业级框架_第4张图片



(3)Constructor类中用于创建对象的API
  • 获取构造器的作用依然是初始化一个对象返回。
方法名称 说明
T newInstance(Object… initargs) 根据指定的构造器创建对象
public void setAccessible(boolean flag) 设置为true,表示取消访问检查,进行暴力反射

范例
package com.app.d3_reflect_constructor;

/**
    老师类
 */
public class Teacher {
    private String name;
    private int age;

    private Teacher() {
        System.out.println("无参构造器被执行");
    }

    public Teacher(String name, int age) {
        System.out.println("有参构造器被执行");
        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 "Teacher{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package com.app.d3_reflect_constructor;

import org.junit.Test;

import java.lang.reflect.Constructor;

/**
    目标:学习使用反射技术获取构造器对象并使用
 */
public class TestTeacher02 {
    @Test
    public void getDeclaredConstructor() throws Exception {
        // a. 获取类对象
        Class c = Teacher.class;

        // b. 获取无参数构造器对象
        Constructor constructor = c.getDeclaredConstructor();
        System.out.println(constructor.getName() + " ---> " + constructor.getParameterCount());

        // c. 根据指定的构造器创建对象
        constructor.setAccessible(true);    //  权限被打开
        Teacher t = (Teacher) constructor.newInstance();    // 如果指定的构造器是private修饰的,请使用上一行代码进行暴力反射(暴力拆箱)
        System.out.println(t);

        System.out.println("-----------------------------");

        // d. 获取有参数构造器对象
        Constructor constructor1 = c.getDeclaredConstructor(String.class, int.class);

        // e. 根据指定的构造器创建对象
        Teacher t1 = (Teacher) constructor1.newInstance("薰悟空", 2000);
        System.out.println(t1);
    }
}

109-Java反射:概述、获取Class类对象、获取Constructor、Field、Method对象、反射作用:绕过编译阶段做企业级框架_第5张图片



总结
  1. 利用反射技术获取构造器对象的方式?
    • getDeclaredConstructors()
    • getDeclaredConstructor(Class… parameterTypes)
  2. 反射得到的构造器可以做什么?
    • 依然是创建对象的
      • public newInstance(Object… initargs)
    • 如果是非public的构造器,需要打开权限(暴力反射),然后再创建对象
      • setAccessible(boolean)
      • 反射可以破坏封装性,私有的也可以执行了


4、获取成员变量对象
  • 使用反射技术获取成员变量对象并使用:

    • 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。

    109-Java反射:概述、获取Class类对象、获取Constructor、Field、Method对象、反射作用:绕过编译阶段做企业级框架_第6张图片


(1)Class类中用于获取成员变量的API
方法名称 说明
Field[] getFields() 返回所有成员变量对象的数组(只能拿public的)
Field[] getDeclaredFields() 返回所有成员变量对象的数组,存在就能拿到
Field getField(String name) 返回单个成员变量对象(只能拿public的)
Field getDeclaredField(String name) 返回单个成员变量对象,存在就能拿到

(2)Field类中用于取值、赋值的API
方法名称 说明
void set(Object obj, Object value) 赋值
Object get(Object obj) 取值

范例
package com.app.d4_reflect_field;

public class Student {
    private String name;
    private int age;
    public static String schoolName;
    public static final String COUNTRY = "中国";

    public Student() {
        System.out.println("无参构造器被执行");
    }

    public Student(String name, int age) {
        System.out.println("有参构造器被执行");
        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 String getSchoolName() {
        return schoolName;
    }

    public static void setSchoolName(String schoolName) {
        Student.schoolName = schoolName;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package com.app.d4_reflect_field;

import org.junit.Test;

import java.lang.reflect.Field;

/**
    目标:使用反射技术获取成员变量:取值和赋值

    Field的方法:给成员变量赋值和取值
        void set(Object obj, Object value): 给对象注入某个成员变量的值
        Object get(Object obj): 获取对象的成员变量的值
        void setAccessible(true): 暴力反射,设置为可以直接访问私有类型的属性
        Class getType(): 获取属性的类型,返回class对象
        String getName(): 获取属性的名称。
 */
public class TestStudent01 {
    @Test
    public void setField() throws Exception {
        // 1、先获取类对象
        Class c = Student.class;

        // 2、提取所有成员变量对象的数组
        Field[] fields = c.getDeclaredFields();

        // 3、遍历一下
        for (Field field : fields) {
            System.out.println(field.getName() + " ===> " + field.getType());
        }

        System.out.println("-------------------------");

        // 4、提取某个成员变量
        Field country = c.getDeclaredField("COUNTRY");

        // 5、获取对象的成员变量的值
        String coun = (String) country.get(c);
        System.out.println(coun);

        Field nameF = c.getDeclaredField("name");
        // 暴力反射,设置为可以直接访问私有类型的属性
        nameF.setAccessible(true);

        System.out.println("-------------------------");

        // 6、给对象注入某个成员变量的值: 赋值
        Student s = new Student();  // 创建对象
        nameF.set(s, "薰悟空");
        System.out.println(s);

        System.out.println("-------------------------");

        // 7、获取对象的成员变量的值: 取值
        String name = (String) nameF.get(s);
        System.out.println(name);
    }
}

109-Java反射:概述、获取Class类对象、获取Constructor、Field、Method对象、反射作用:绕过编译阶段做企业级框架_第7张图片



总结
  1. 利用反射技术获取成员变量的方式?
    • 获取类中成员变量对象的方法
      • getDeclaredFields()
      • getDeclaredField(String name)
  2. 反射得到成员变量可以做啥?
    • 依然是在某个对象中取值和赋值
      • void set(Object obj, Object value)
      • Object get(Object obj)
    • 如果某成员变量是非public的,需要打开权限(暴力反射),然后再取值、赋值
      • setAccessible(boolean)


5、获取方法对象
  • 使用反射技术获取方法对象并使用:

    • 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。

    109-Java反射:概述、获取Class类对象、获取Constructor、Field、Method对象、反射作用:绕过编译阶段做企业级框架_第8张图片


(1)Class类中用于获取成员方法的API
方法名称 说明
Method[] getMethods() 返回所有成员方法对象的数组(只能拿public的)
Method[] getDeclaredMethods() 返回所有成员方法对象的数组,存在就能拿到
Method getMethod(String name, Class< ? >… parameterTypes) 返回单个成员方法对象(只能拿到public的)
Method getDeclaredMethod(String name, Class< ? >… parameterTypes) 返回单个成员方法对象,存在就能拿到

(2)Method类中用于触发执行的方法
方法名称 说明
Object invoke(Object obj, Object… args) 运行方法
参数一:用obj对象调用该方法
参数二:调用方法的传递的参数(如果没有就不写)
返回值:方法的返回值(如果没有就不写)

范例
package com.app.d5_reflect_method;

public class Cat {
    private String name;

    public Cat() {

    }

    public void run() {
        System.out.println("猫跑得飞快~~");
    }

    // 私有方法
    private void eat() {
        System.out.println("猫喜欢吃鱼!");
    }

    private String eat(String food) {
        System.out.println("猫吃" + food);
        return "吃得非常开心~~";
    }

    public static void inAdd() {
        System.out.println("我们正在学习Java!");
    }

    public Cat(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                '}';
    }
}
package com.app.d5_reflect_method;

import org.junit.Test;

import java.lang.reflect.Method;

/**
    目标:使用反射技术获取方法对象并触发执行
 */
public class TestCat01 {
    // a.先获取对象类
    public static Class c = Cat.class;

    /**
     * 1、获取所有方法对象的数组
     */
    @Test
    public void getDeclaredMethods() {
        System.out.println("1、获取所有方法对象的数组:");

        // b.获取所有方法对象的数组
        Method[] methods = c.getDeclaredMethods();
        // c.遍历一下
        for (Method method : methods) {
            System.out.println("方法名称:" + method.getName() +
                    ",返回值类型:" + method.getReturnType() +
                    ",参数个数:" + method.getParameterCount());
        }

        System.out.println();
    }

    /**
     * 2、获取某个方法对象
     */
    @Test
    public void getDeclaredMethod() throws Exception {
        System.out.println("2、获取某个方法对象:");
        // b.获取某个方法对象
        Method method = c.getDeclaredMethod("eat");
        Method method1 = c.getDeclaredMethod("eat", String.class);
        Method method2 = c.getDeclaredMethod("inAdd");

        // 如果方法是private修饰的,就暴力打开权限
        method.setAccessible(true);
        method1.setAccessible(true);

        // c.触发方法的执行
        Cat cat = new Cat();
        // 注意:方法如果是无返回值的,那么返回的是null
        Object result = method.invoke(cat);
        System.out.println(result);

        System.out.println("-----------------");

        Object result1 = method1.invoke(cat, "猫粮");
        System.out.println(result1);

        System.out.println("-----------------");

        method2.invoke(cat);

        System.out.println();
    }
}

109-Java反射:概述、获取Class类对象、获取Constructor、Field、Method对象、反射作用:绕过编译阶段做企业级框架_第9张图片



总结
  1. 利用反射技术获取成员方法对象的方式?
    • 获取类中成员方法对象
      • getDeclaredMethods()
      • getDeclaredMethod(String name, Class… parameterTypes)
  2. 反射得到成员方法对象可以做啥?
    • 依然是在某个对象中触发该方法执行
      • Object invoke(Object obj, Object… args)
    • 如果某成员方法是非public修饰的,需要打开权限(暴力反射),然后再触发执行
      • setAccessible(boolean)



6、反射的作用[拓展]
  • 目前只是拓展一下反射的基本作用,要是真想知道反射的真正强大之处,还需学到高级框架的底层源码才会知道!!
  • 所以不着急,慢慢来!!

(1)绕过编译阶段为集合添加数据
  • 反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以 为集合存入其他任意类型的元素的

    • 之前在创建集合时会声明泛型,比如以下程序中声明的泛型是Integer类型,那么此集合只能添加Int类型的数据,一旦添加其他类型的数据就会在编译时报错,但是如果用反射技术,就可以强行往声明了泛型的集合添加其他类型的数据:

      ArrayList<Integer> list = new ArrayList<>();
      list.add(100);
      // list.add("中国"); // 报错
      list.add(99);
      
    • 原因:

      • 泛型只是在编译阶段可以约束集合只能操作某种数据类型,在 编译成Class文件进入运行阶段时,其真实类型都是 ArrayList 了,泛型相当于被擦除了。
      package com.app.d6_reflect_genericity;
      
      import java.lang.reflect.Method;
      import java.util.ArrayList;
      
      /**
          目标:反射实现泛型擦除后,加入其他类型的元素
       */
      public class ReflectDemo1 {
          public static void main(String[] args) throws Exception {
              // 1、创建两个不同泛型的集合
              ArrayList<String> list1 = new ArrayList<>();
              ArrayList<Integer> list2 = new ArrayList<>();
      
              // 2、得到两个集合的class文件
              System.out.println(list1.getClass());
              System.out.println(list2.getClass());
      
              // 3、判断两个集合的class文件是否相同
              System.out.println(list1.getClass() == list2.getClass());   // true
      
              System.out.println("--------------------------");
      
              // 4、创建一个泛型的集合,用于实现泛型擦除后,加入不同类型的数据
              ArrayList<Integer> list3 = new ArrayList<>();
              list3.add(123);
              list3.add(24);
      //        list3.add("我爱中国!"); // 报错
      //        list3.add(123.33);  // 报错
      
              // 5、得到泛型集合list3的Class对象
              Class c = list3.getClass();
      
              // 6、得到c类中的add方法
              Method add = c.getDeclaredMethod("add", Object.class);
      
              // 7、添加任意类型的数据到list3集合中
              boolean rs1 = (boolean) add.invoke(list3, "我爱中国!");
              boolean rs2 = (boolean) add.invoke(list3, 123.33);
              System.out.println(rs1);
              System.out.println(rs2);
      
              System.out.println(list3);
      
              System.out.println("--------------------------");
      
              // 另一种方式实现泛型擦除后,加入其他类型的元素
              // a.将泛型集合list3赋值给没有约定泛型的集合list4
              ArrayList list4 = list3;
              
              // b.添加其他类型的元素
              list4.add("敖德彪");
              list4.add(false);
              list4.add(66.6);
      
              System.out.println(list3);
          }
      }
      
      class java.util.ArrayList
      class java.util.ArrayList
      true
      --------------------------
      true
      true
      [123, 24, 我爱中国!, 123.33]
      --------------------------
      [123, 24, 我爱中国!, 123.33, 敖德彪, false, 66.6]
      
      Process finished with exit code 0
      
      

总结
  1. 反射为何可以给约定了泛型的集合存入其他类型的元素?
    • 编译成Class文件进入运行阶段时,泛型会自动擦除
    • 反射是作用在运行时的技术,此时已经不存在泛型了


(2)通用框架的底层原理
  • 案例:反射做通用框架

    • 需求:
      • 给你任意一个对象,在不清楚对象字段的情况,可以把对象的字段名称和对应值存储到文件中去。
    • 分析实现:
      1. 定义一个方法,可以接收任意类的对象
      2. 每次收到一个对象后,需要解析这个对象的全部成员变量名称
      3. 这个对象可能是任意的,那么怎么样才可以知道这个对象的全部成员变量名称呢?
      4. 使用反射技术获取对象的Class类对象
      5. 获取全部成员变量信息
      6. 遍历全部成员变量信息
      7. 提取该成员变量在对象中的具体值
      8. 将成员变量名称和值存入到文件中去即可
    package com.app.d7_reflect_framework;
    
    /**
        1、创建对象:学生类
     */
    public class Student {
        /**
            学生的属性:姓名、性别、年龄、班级、爱好
         */
        private String name;
        private char sex;
        private int age;
        private String className;
        private String hobby;
    
        /**
            无参数构造器
         */
        public Student() {
    
        }
    
        /**
         * 有参数构造器
         * @param name      姓名
         * @param sex       性别
         * @param age       年龄
         * @param className 班级
         * @param hobby     爱好
         */
        public Student(String name, char sex, int age, String className, String hobby) {
            this.name = name;
            this.sex = sex;
            this.age = age;
            this.className = className;
            this.hobby = hobby;
        }
    
    
        /**
         * 提供全套get、set方法:暴露其取值和赋值
         */
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public char getSex() {
            return sex;
        }
    
        public void setSex(char sex) {
            this.sex = sex;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getClassName() {
            return className;
        }
    
        public void setClassName(String className) {
            this.className = className;
        }
    
        public String getHobby() {
            return hobby;
        }
    
        public void setHobby(String hobby) {
            this.hobby = hobby;
        }
    
    
        /**
         * 重写toString方法
         */
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", sex=" + sex +
                    ", age=" + age +
                    ", className='" + className + '\'' +
                    ", hobby='" + hobby + '\'' +
                    '}';
        }
    }
    
    package com.app.d7_reflect_framework;
    
    /**
        1、创建对象:老师类
     */
    public class Teacher {
        /**
            老师的属性:姓名、性别、薪水
         */
        private String name;
        private char sex;
        private double salary;
    
        /**
            无参数构造器
         */
        public Teacher() {
    
        }
    
        /**
            有参数构造器
         * @param name   姓名
         * @param sex    性别
         * @param salary 薪水
         */
        public Teacher(String name, char sex, double salary) {
            this.name = name;
            this.sex = sex;
            this.salary = salary;
        }
    
    
        /**
            提供get、set方法:暴露其取值和赋值
         */
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public char getSex() {
            return sex;
        }
    
        public void setSex(char sex) {
            this.sex = sex;
        }
    
        public double getSalary() {
            return salary;
        }
    
        public void setSalary(double salary) {
            this.salary = salary;
        }
    
    
        /**
            重写toString方法
         */
        @Override
        public String toString() {
            return "Teacher{" +
                    "name='" + name + '\'' +
                    ", sex=" + sex +
                    ", salary=" + salary +
                    '}';
        }
    }
    
    package com.app.d7_reflect_framework;
    
    import java.io.FileOutputStream;
    import java.io.PrintStream;
    import java.lang.reflect.Field;
    
    /**
        2、创建框架类
     */
    public class MyBatisUtil {
        /**
         * 3、定义保存所有类型对象的方法
         * @param obj   传入的对象
         */
        public static void saveAllObject(Object obj) {
            try (
                    // d. 创建打印流,包装一个文件字节输出流:参数一是输出目标文件相对路径;参数二是每次输出都会在文件末尾追加数据。
                    PrintStream ps = new PrintStream(new FileOutputStream("day14-junit-reflect-annotation-proxy-app/src/data.txt", true));
            ) {
                // a. 得到该对象的Class类对象
                Class c = obj.getClass();
    
                // e. 输出当前类名到文件中
                // c.getSimpleName(): 获取当前类名;c.getName(): 获取类的全限名(包名+类名)
                ps.println("===========" + c.getSimpleName() + "===========");
    
                // b. 提取该对象的全部成员变量
                Field[] fields = c.getDeclaredFields();
    
                // c. 遍历全部成员变量,得到信息
                for (Field field : fields) {
                    // (c-1) 获取成员变量的名称
                    String name = field.getName();
    
                    // (c-2) 由于对象的成员变量都是私有的,所以需要暴力反射
                    field.setAccessible(true);
    
                    // (c-3) 获取该成员变量在obj对象中的具体值(取值)
                    String value = field.get(obj) + ""; // 得到值后拼接一个空字符串:意思就是把任何值都转成字符串存入到文件中
    
                    // f. 将成员变量名称和具体值输出到目标文件中
                    ps.println(name + "=" + value);
                }
                
                System.out.println("保存成功!");
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    package com.app.d7_reflect_framework;
    
    /**
        目标:通过使用反射做通用框架支持保存任意对象的具体信息,可以理解到反射的作用
        需求:
            给你任意一个对象,在不清楚对象字段的情况,可以把对象的字段名称和对应值存储到文件中。
     */
    public class ReflectDemo {
        public static void main(String[] args) {
            // 4、创建学生对象
            Student stu1 = new Student();
            stu1.setName("孙悟空");
            stu1.setSex('男');
            stu1.setAge(2000);
            stu1.setClassName("天宫舔狗99班");
            stu1.setHobby("大闹天宫");
            // a. 将此学生对象的信息保存到目标文件中
            MyBatisUtil.saveAllObject(stu1);
    
            // 5、创建老师对象
            Teacher tea1 = new Teacher();
            tea1.setName("玉皇大帝");
            tea1.setSex('男');
            tea1.setSalary(10000);
            // a. 将此老师对象的信息保存到目标文件中
            MyBatisUtil.saveAllObject(tea1);
        }
    }
    

测试

109-Java反射:概述、获取Class类对象、获取Constructor、Field、Method对象、反射作用:绕过编译阶段做企业级框架_第10张图片


109-Java反射:概述、获取Class类对象、获取Constructor、Field、Method对象、反射作用:绕过编译阶段做企业级框架_第11张图片


109-Java反射:概述、获取Class类对象、获取Constructor、Field、Method对象、反射作用:绕过编译阶段做企业级框架_第12张图片



总结
  1. 反射的作用是?
    • 可以在运行时得到一个类的全部成分,然后操作
    • 可以破坏封装性。(很突出)
    • 也可以破坏泛型的约束性。(很突出)
    • 更重要的用途是适合做Java高级框架

你可能感兴趣的:(JavaSE基础进阶篇,java,开发语言)