• 我不得不学的反射


    什么是反射

    反射是指对于任何一个Class类,在运行时都可以直接得到这个类的全部成分
    这种运行时动态获取信息以及动态调用类中成分的能力称为java的反射机制

    获取字节码文件

    获取反射对象

    方法一

    public static void main(String[] args) throws Exception {
            Class class1=Class.forName("reflect.Student");
            System.out.println(class1);
        }
    
    • 1
    • 2
    • 3
    • 4

    方法二

    Class class2=Student.class;
            System.out.println(class2);
    
    • 1
    • 2

    方法三

    Student student=new Student();
            Class class3=student.getClass();
            System.out.println(class3);
    
    • 1
    • 2
    • 3

    获取构造器对象

    获取全部的构造器,但是只能获取public修饰的

    @Test
        public void getConstructors(){
            //获取反射对象
            Class c = Student.class;
            //提取所有的构造器对象
            Constructor []constructors= c.getConstructors();
    
            //遍历构造器
            for (Constructor constructor : constructors) {
                System.out.println(constructor.getName()+"===>"+constructor.getParameterCount());
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    获取全部的构造器,无论权限

    @Test
        public void getDeclaredConstructor(){
            Class c = Student.class;
            //提取所有的构造器对象
            Constructor []constructors= c.getDeclaredConstructors();
    
            //遍历构造器
            for (Constructor constructor : constructors) {
                System.out.println(constructor.getName()+"===>"+constructor.getParameterCount());
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    获取指定的构造器,只能获取public

    @Test
        public void getConstructor() throws Exception {
            Class c = Student.class;
            Constructor constructor=c.getConstructor();
    
            System.out.println(constructor.getName()+"===>"+constructor.getParameterCount());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    获取指定构造器,无论权限

     @Test
        public void getDeclaredConstructor() throws Exception {
            Class c = Student.class;
            Constructor constructor1= c.getDeclaredConstructor();
            Constructor constructor2= c.getDeclaredConstructor(String.class,int.class);
    
    
            System.out.println(constructor1.getName()+"===>"+constructor1.getParameterCount());
            System.out.println(constructor2.getName()+"===>"+constructor2.getParameterCount());
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    获取构造器并返回一个初始化对象

    @Test
        public void getback() throws Exception {
            Class c = Student.class;
            Constructor constructor1= c.getDeclaredConstructor();
            Constructor constructor2= c.getDeclaredConstructor(String.class,int.class);
    
            //遇到私有的反射器,可以暴力反射
            constructor1.setAccessible(true);
    
            Student student1=(Student) constructor1.newInstance();
            Student student2=(Student) constructor2.newInstance("张三",10086);
    
            System.out.println(student1);
            System.out.println(student2);
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    反射可以破坏封装性,运行私密的

    获取成员对象

    获取所有的对象,无论权限

    @Test
        public void getDeclardeFields(){
            Class c=Student.class;
    
            Field[] fields= c.getDeclaredFields();
    
            for (Field field : fields) {
                System.out.println(field.getName()+"===>"+field.getType());
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    获取单个对象,无论权限

    @Test
        public void getDeclardeField() throws Exception {
            Class c=Student.class;
    
    
            Field field1=c.getDeclaredField("age");
            System.out.println(field1.getName()+"===>"+field1.getType());
    
            Field field2=c.getDeclaredField("name");
            System.out.println(field2.getName()+"===>"+field2.getType());
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    给成员变量赋值

    @Test
        public void getback() throws Exception {
            Class c=Student.class;
    
            Field fieldAge= c.getDeclaredField("age");
    
            fieldAge.setAccessible(true);
    
            Student s=new Student();
            fieldAge.set(s,18);
            System.out.println(s);
    
            int age=(int)fieldAge.get(s);
            System.out.println(age);
            
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    同样的因为成员变量为私有,需要用到暴力反射

    获取方法

    获取所有的方法,无论权限

    @Test
        public void getDeclaredMethods(){
            Class c=Student.class;
    
            Method[] methods=c.getDeclaredMethods();
    
            for (Method method : methods) {
                System.out.println(method.getName()+"返回值类型"+method.getReturnType()+"参数数量"+method.getParameterCount());
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    获取指定方法,无论权限

    @Test
        public void getDeclaredMethod() throws Exception {
            Class c=Student.class;
    
    
            Method method1=c.getDeclaredMethod("run");
            System.out.println(method1.getName()+"返回值类型"+method1.getReturnType()+"参数数量"+method1.getParameterCount());
    
            Method method2=c.getDeclaredMethod("run",String.class);
            System.out.println(method2.getName()+"返回值类型"+method2.getReturnType()+"参数数量"+method2.getParameterCount());
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    获取方法并使用

    @Test
        public void getback() throws Exception {
            Class c=Student.class;
    
            Method method1=c.getDeclaredMethod("run");
            Method method2=c.getDeclaredMethod("run",String.class);
    
    
            method1.setAccessible(true);
            method2.setAccessible(true);
    
            Student s=new Student();
    
    
            Object result1=method1.invoke(s);
            System.out.println(result1);
    
            Object result2=method2.invoke(s,"李四");
            System.out.println(result2);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    反射的一些简单应用

    绕泛型约束

    public static void main(String[] args) {
            ArrayList<String> list1=new ArrayList<>();
            ArrayList<Integer>list2=new ArrayList<>();
    
            System.out.println(list1.getClass());
            System.out.println(list2.getClass());
    
            System.out.println(list1.getClass()==list2.getClass());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述
    首先们可以通过上述的一个小例子看到,在无论是何种类型的ArrayList集合,其类型都是相同的,这就意味着,当代码编译成Class文件进入运行阶段之后,泛型会自动擦除,而反射是恰恰是针对运行阶段的技术,很显然我们可以绕过泛型的约束

    ArrayList<Integer>list3=new ArrayList<>();
            list3.add(1);
            list3.add(114514);
            list3.add(1919810);
    
            Class c=list3.getClass();
            Method method=c.getDeclaredMethod("add", Object.class);
            method.invoke(list3,"浩二");
            System.out.println(list3);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述
    其实还可以通过地址直接绕过泛型的约束

    public static void main(String[] args) {
            ArrayList<Integer> list3=new ArrayList<>();
            list3.add(1);
            list3.add(114514);
            list3.add(1919810);
    
            ArrayList list4=list3;
            list4.add("浩二");
            list4.add(false);
            System.out.println(list3);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述
    这么看来泛型的约束好像和马奇诺防线一样,谁都能绕

    通用框架的底层原理,简易版

    先创建两个要读取的类

    Student类

    public class Student {
        private String name;
        private char sex;
        private int age;
        private String className;
        private String hobby;
    
        public Student() {
        }
    
        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;
        }
    
        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;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", sex=" + sex +
                    ", age=" + age +
                    ", className='" + className + '\'' +
                    ", 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

    Teacher类

    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
    • 48

    创建一个工具类用于得到类的内容,并打印

    public class Utils {
        public static void save(Object obj) {
            try (PrintStream ps=new PrintStream(new FileOutputStream("junit_class/src/data.txt",true)))
            {
                Class c = obj.getClass();
    
                //getSimpleName获取当前类名,getName获取包名加类名
                ps.println("============="+c.getSimpleName()+"================");
                Field[] fields = c.getDeclaredFields();
    
                for (Field field : fields) {
                    String name = field.getName();
                    //获取成员变量的值,采用拼字符串的方式,防止类型强转出错
                    field.setAccessible(true);
                    String value = field.get(obj) + "";
                    ps.println(name +"="+value);
                }
            } 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

    最后是主程序

    public class reflectDemo {
        public static void main(String[] args) {
            Student student=new Student();
            student.setName("浩二");
            student.setAge(114514);
            student.setSex('难');
            student.setClassName("下北泽高级中学");
            student.setHobby("蕨");
            Utils.save(student);
    
            Teacher teacher=new Teacher();
            teacher.setName("静可爱");
            teacher.setSex('女');
            teacher.setSalary(100000);
            Utils.save(teacher);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    看看文件里的内容
    在这里插入图片描述
    完美结束

  • 相关阅读:
    【LeetCode】Day96-第一个唯一字符&赎金信&字母异位词
    Java中常见包装类型Integer、BigDecimal等特点说明
    独立站+TikTok是下个风口吗
    【重磅+测评】Jetbrain发布Rust IDE,免费使用一年
    [oeasy]python001_先跑起来_python_三大系统选择_windows_mac_linux
    技术干货|昇思MindSpore初级课程上线:从基本概念到实操,1小时上手!
    Android hid发送apdu格式数据
    c++视觉处理 ------ 反向投影图和直方图的变化
    angular项目启动报错
    【SpringBoot笔记28】SpringBoot集成ES数据库之操作doc文档(创建、更新、删除、查询)
  • 原文地址:https://blog.csdn.net/qq_61057438/article/details/127413936