• P02 反射


    系统:Win10
    Java:1.8.0_333
    IDEA:2020.3.4
    Gitee:https://gitee.com/lijinjiang01/JavaWeb

    1.反射概述

    1.1 反射的基本作用

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

    1.2 反射的关键

    反射第一步都是先得到编译后的 Class 类对象,然后就可以得到 Class 的全部成分
    反射的核心思想和关键就是:得到编译以后的 class 文件对象
    在这里插入图片描述

    2.反射获取类对象

    在这里插入图片描述

    获取 Class 类对象的三种方式:

    2.1 forName(String className)

    Class 类中的一个静态方法:forName(String className)

    Class c1 = Class.forName("com.lijinjiang.reflect01_class.Student");
    
    • 1

    2.2 类名.class

    Class c2 = Student.class;
    
    • 1

    2.3 对象.getClass()

    利用 Object 对象的 getClass() 方法获取对象对应类的 Class 对象

    Student stu = new Student();
    Class c3 = stu.getClass();
    
    • 1
    • 2

    3.反射获取构造器对象在这里插入图片描述

    3.1 Class 类中用于获取构造器的方法

    方法说明
    Constructor[] getConstructors()返回所有公共构造器对象的数组
    Constructor[] getDeclaredConstructors()返回所有构造器对象的数组,存在就能拿到
    Constructor getConstructor(Class… parameterTypes)返回指定的公共构造器对象
    Constructor getDeclaredConstructor(Class… parameterTypes)返回指定的构造器对象,存在就能拿到

    3.2 Constructor 类中常用方法

    方法说明
    T newInstance(Object… initargs)根据执行的构造器创建对象
    void setAccessible(boolean flag)设置为true,表示取消访问检查,进行暴力反射

    3.3 测试案例

    首先创建 Student 类对象

    public class Student {
        private String name;
        private int age;
    
        private Student() {
            System.out.println("无参构造器执行");
        }
    
        private Student(String name){
            this.name = name;
            System.out.println("有参构造器执行");
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
            System.out.println("全参构造器执行");
        }
    
        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 +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    测试获取构造器方法

    import org.junit.Test;
    import java.lang.reflect.Constructor;
    
    public class TestConstructor01 {
        // 1.getConstructors
        @Test
        public void testGetConstructors() {
            // 1.获取类对象
            Class c = Student.class;
            // 2.获取所有类对象的公共构造器
            Constructor[] constructors = c.getConstructors();
            // 3.遍历
            for (Constructor constructor : constructors) {
                System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
            }
    
        }
    
        // 2.getDeclaredConstructors
        @Test
        public void testGetDeclaredConstructors() {
            // 1.获取类对象
            Class c = Student.class;
            // 2.获取所有类对象的构造器
            Constructor[] constructors = c.getDeclaredConstructors();
            // 3.遍历
            for (Constructor constructor : constructors) {
                System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
            }
    
        }
    
        // 3.getConstructor(Class... parameterTypes)
        @Test
        public void testGetConstructor() throws Exception {
            // 1.获取类对象
            Class c = Student.class;
            // 2.获取所有类对象的构造器
            Constructor constructor = c.getConstructor(String.class, int.class);
            // 3.输出
            System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
        }
    
        // 4.getDeclaredConstructor(Class... parameterTypes)
        @Test
        public void testGetDeclaredConstructor() throws Exception {
            // 1.获取类对象
            Class c = Student.class;
            // 2.获取所有类对象的构造器
            Constructor constructor = c.getDeclaredConstructor();
            // 3.输出
            System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    测试使用构器创建对象方法

    import org.junit.Test;
    import java.lang.reflect.Constructor;
    
    public class TestConstructor02 {
        // 1.T newInstance(Object... initargs)
        @Test
        public void testNewInstance() throws Exception {
            // 1.获取类对象
            Class c = Student.class;
            // 2.获取Student(String name)构造器,并以此创建对象
            Constructor c01 = c.getDeclaredConstructor(String.class);
            c01.setAccessible(true); // 暴力反射
            Student stu01 = (Student) c01.newInstance("张三");
            System.out.println(stu01);
    
            // 3.获取Student(String name, int age)构造器,并以此创建对象
            Constructor c02 = c.getDeclaredConstructor(String.class,int.class);
            Student stu02 = (Student) c02.newInstance("李四",27);
            System.out.println(stu02);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    4.反射获取成员变量对象

    在这里插入图片描述

    4.1 Class 类中用于获取成员变量的方法

    方法说明
    Field[] getFields()返回所有公共成员变量对象的数组
    Field[] getDeclaredFields()返回所有成员变量对象的数组,存在就能拿到
    Field getField(String name)返回指定公共成员变量对象
    Field getDeclaredField(String name)返回指定成员变量对象,存在就能拿到

    4.2 Field 类中常用方法

    方法说明
    void set(Object obj, Object value)给指定对象的此成员变量设置指定的新值
    Object get(Object obj)获取指定对象的该成员变量的值
    void setAccessible(boolean flag)暴力反射,设置为true可以直接访问私有属性的变量
    Class getType()获取变量的类型,返回类型Class对象
    String getName()获取变量的名称

    4.3 测试案例

    首先创建 Student 类对象

    public class Student {
        private String name;
        private int age;
        public static String school;
        public static final String COUNTRY = "中国";
    
        public Student() {
        }
    
        private Student(String name) {
            this.name = name;
        }
    
        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;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    测试获取成员变量的方法

    import org.junit.Test;
    import java.lang.reflect.Field;
    
    public class TestField01 {
        // 1.getFields()
        // 2.getDeclaredFields()
        @Test
        public void testGetDeclaredFields() {
            // 1.获取 class 对象
            Class c = Student.class;
            // 2.获取公共成员变量数组
            Field[] fields = c.getDeclaredFields();
            // 3.遍历
            for (Field field : fields) {
                System.out.println(field.getName() + "===>" + field.getType());
            }
        }
        // 3.getField(String name)
        // 4.getDeclaredField(String name)
        @Test
        public void testGetDeclaredField() throws Exception {
            // 1.获取 class 对象
            Class c = Student.class;
            // 2.获取公共成员变量数组
            Field field = c.getDeclaredField("age");
            // 3.输出
            System.out.println(field.getName() + "===>" + field.getType());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    测试成员变量的赋值和取值方法

    import org.junit.Test;
    import java.lang.reflect.Field;
    
    public class TestField02 {
        @Test
        public void testSetField() throws Exception {
            // 1.获取class对象
            Class c = Student.class;
            // 2.获取指定成员变量
            Field field = c.getDeclaredField("age");
            field.setAccessible(true);
            // 3.赋值
            Student stu01 = new Student();
            field.set(stu01, 18);
            System.out.println(stu01);
    
            // 4.取值
            Student stu02 = new Student("李四", 27);
            int age = (int) field.get(stu02);
            System.out.println(age);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    5.反射获取方法对象

    在这里插入图片描述

    5.1 Class 类中用于获取成员方法的方法

    方法说明
    Method[] getMethods()返回所有公共成员方法对象的数组
    Method[] getDeclaredMethods()返回所有成员方法对象的数组,存在就能拿到
    Method getMethod(String name, Class… parameterTypes)返回指定公共成员方法对象
    Method getDeclaredMethod(String name, Class… parameterTypes)返回指定成员方法对象,存在就能拿到

    5.2 Method 类中常用方法

    方法说明
    Object invoke(Object obj, Object… args)运行方法
    参数一:用obj对象调用该方法
    参数二:调用方法传递的参数(如果没有就不写)
    返回值:方法的返回值(如果没有就不写)
    void setAccessible(boolean flag)暴力反射,设置为true可以直接调用私有方法运行

    5.3 测试案例

    首先创建 Dog 类对象

    public class Dog {
        private String name;
    
        public Dog() {
        }
    
        public Dog(String name) {
            this.name = name;
        }
    
        public void run() {
            System.out.println("小狗跑的飞快");
        }
    
        private void eat() {
            System.out.println("狗吃骨头");
        }
    
        private String eat(String name) {
            System.out.println("狗在吃" + name);
            return "吃的很开心";
        }
    
        public static void inAddr() {
            System.out.println("在上海有一只单身狗");
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    测试获取成员方法的方法以及测试方法运行的方法

    import org.junit.Test;
    import java.lang.reflect.Method;
    
    public class TestMethod01 {
        // 1.getMethods()
        // 2.getDeclaredMethods()
        @Test
        public void testGetDeclaredMethods() {
            // 1.获取 class 对象
            Class c = Dog.class;
            // 2.获取成员方法数组
            Method[] methods = c.getDeclaredMethods();
            // 3.遍历
            for (Method method : methods) {
                System.out.println(method.getName() + " 返回值类型" + method.getReturnType() + " 参数个数" + method.getParameterCount());
            }
        }
    
        // 3.getMethod(String name, Class... parameterTypes)
        // 4.getDeclaredMethod(String name, Class... parameterTypes)
        @Test
        public void testGetDeclaredMethod() throws Exception {
            // 1.获取 class 对象
            Class c = Dog.class;
            // 2.获取成员方法数组
            Method method01 = c.getDeclaredMethod("eat");
            method01.setAccessible(true);
            Method method02 = c.getDeclaredMethod("eat",String.class);
            method02.setAccessible(true);
            // 3.执行方法
            Dog dog = new Dog();
            Object res01 = method01.invoke(dog);
            Object res02 = method02.invoke(dog, "稀饭");
            System.out.println(res01);
            System.out.println(res02);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    6.反射的作用

    6.1 绕过编译阶段为集合添加数据

    反射是作用在运行时的技术,此时集合的泛型将不能再产生约束了,此时是可以为集合存入其他任意类型的元素的
    在这里插入图片描述

    泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成 Class 文件进入运行阶段的时候,其真实类型都是 ArrayList 了,泛型相当于被擦除了
    代码如下:

    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.List;
    
    public class ReflectDemo {
        public static void main(String[] args) throws Exception {
            List<String> list01 = new ArrayList<>();
            List<Integer> list02 = new ArrayList<>();
    
            System.out.println(list01.getClass());
            System.out.println(list02.getClass());
    
            System.out.println(list01.getClass() == list02.getClass()); // ArrayList.class
    
            System.out.println("==============================");
    
            List<Integer> list03 = new ArrayList<>();
            list03.add(100);
            list03.add(200);
            // list03.add("三百");
            // 1.获取class对象
            Class c = list03.getClass();
            // 2.获取指定method
            Method method = c.getMethod("add",Object.class);
            // 3.运行该方法
            boolean b = (boolean) method.invoke(list03, "三百");
            System.out.println(b);
            System.out.println(list03);
    
            System.out.println("==============================");
    
            List list04 = list03;
            list04.add("四百");
            list04.add(true);
            System.out.println(list03);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    6.2 通过框架的底层原理

    6.2.1 需求分析

    需求:给任意一个对象,在不清楚对象字段的情况下,可以把对象的字段名称和对应值存储到文件中去
    分析

    1. 定义一个方法,可以接收任意类的对象
    2. 使用反射获取对象的 Class 类对象,然后获取全部成员变量信息
    3. 遍历成员变量信息,然后提取本成员变量在对象中的具体值
    4. 存入成员变量名称和值到文件中去即可

    6.2.2 代码实例

    创建 Student、Teacher 类

    public class Student {
        private String name;
        private char sex;
        private int age;
        private String classroom;
        private String hobby;
    
        public Student() {
        }
        
        public Student(String name, char sex, int age, String classroom, String hobby) {
            this.name = name;
            this.sex = sex;
            this.age = age;
            this.classroom = classroom;
            this.hobby = hobby;
        }
    
        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 getClassroom() {
            return classroom;
        }
    
        public void setClassroom(String classroom) {
            this.classroom = classroom;
        }
    
        public String getHobby() {
            return hobby;
        }
    
        public void setHobby(String hobby) {
            this.hobby = hobby;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", sex=" + sex +
                    ", age=" + age +
                    ", classroom='" + classroom + '\'' +
                    ", hobby='" + hobby + '\'' +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    public class Teacher {
        private String name;
        private char sex;
        private double salary;
    
        public Teacher() {
        }
    
        public Teacher(String name, char sex, double salary) {
            this.name = name;
            this.sex = sex;
            this.salary = salary;
        }
    
        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;
        }
    
        @Override
        public String toString() {
            return "Teacher{" +
                    "name='" + name + '\'' +
                    ", sex=" + sex +
                    ", salary=" + salary +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    创建工具类

    import java.io.FileOutputStream;
    import java.io.PrintStream;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    public class MybatisUtil {
        /**
         * 保存任意类型的对象
         */
        public static void save(Object obj) {
            try {
                PrintStream ps = new PrintStream(new FileOutputStream(
                        "P02_Reflect/src/com/lijinjiang/reflect06_framework/data.txt", true));
                // 1.获取class对象
                Class c = obj.getClass(); // c.getSimpleName() 获取当前类名  c.getName() 获取全限名:包名+类名
                String simpleName = c.getSimpleName();
                ps.println("===============" + simpleName + "===============");
                // 2.获取全部成员变量
                Field[] fields = c.getDeclaredFields();
                // 3.获取成员变量的值
                for (Field field : fields) {
                    field.setAccessible(true);
                    String name = field.getName();
                    String value = field.get(obj) + "";
                    ps.println(name + "=" + value);
                }
                ps.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    创建测试类

    public class ReflectDemo {
        public static void main(String[] args) {
            Teacher teacher01 = new Teacher("古越涛", '男', 3999.9);
            Teacher teacher02 = new Teacher("裴佩", '女', 4999.0);
            Student student = new Student("蓝菲琳", '女', 18, "三年八班", "唱歌、跳舞");
            MybatisUtil.save(teacher01);
            MybatisUtil.save(teacher02);
            MybatisUtil.save(student);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    6.2.3 运行结果

    在这里插入图片描述

  • 相关阅读:
    部分产品小汇总
    结构的类型
    Elasticsearch是如何实现Master选举的?
    学习笔记7--交通环境行为预测
    Banana Pi BPI-W3 RK3588平台驱动调试篇 [ PCIE篇二 ] - PCIE的开发指南
    【爬虫】8.1. 使用OCR技术识别图形验证码
    软件包的管理
    2022/7/27 算力-价格明细
    设计模式之【策略模式】
    利用pytorch可以实现手写字体的识别吗 基于深度学习算法
  • 原文地址:https://blog.csdn.net/qq_35132089/article/details/126964963