• Java反射--师承韩顺平


    java反射详解

    做项目必须熟练的技能

    1. 介绍

    问:反射是干什么的?
    场景:根据一个配置文件的信息,创建一个类的实例。
    通过反射可以实现动态加载的功能。。

    1)反射允许程序执行期间通过Reflection API 获取任何类的内部信息
    2)加载完类之后,堆中产生一个Class类的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息

    项目框架底层就是反射,
    优点:可以动态创建和使用对象,灵活
    缺点:因为基本是解释执行,运行速度有影响

    Class介绍:
    在这里插入图片描述

    反射示意图:
    在这里插入图片描述

    2. 反射操作

    在这里插入图片描述
    上代码:

    在这里插入图片描述

    package com.wts.reflection;
    
    import com.wts.reflection.car.Car;
    
    import java.lang.reflect.Field;
    
    public class Reflection {
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
            String classPath = "com.wts.reflection.car.Car";
    
            //1.获取Car类 对应的Class类
            Class<?> cls = Class.forName(classPath);
    
            //2.输出cls
            System.out.println(cls);//--显示的cls对象    //class com.wts.reflection.car.Car
            System.out.println(cls.getClass());//--输出cls的运行类    //class java.lang.Class
    
            //3.得到包名
            System.out.println(cls.getPackage().getName());//--包名   //com.wts.reflection.car
    
            //4.得到类名
            System.out.println(cls.getName());//--类名    //com.wts.reflection.car.Car
    
            //5.创建实例对象
            Car car = (Car) cls.newInstance();
            System.out.println(car);//toString  //Car{brand='宝马', price=50000, color='白色'}
    
            //6.通过反射获取属性 brand
            Field brand = cls.getField("brand");
            System.out.println(brand.get(car));//*brand  //宝马
    
            //7.通过反射给属性赋值
            brand.set(car, "奔驰");
            System.out.println(brand.get(car));//奔驰
    
            //8.获取所有属性
            System.out.println("---------");
            Field[] fields = cls.getFields();
            for (Field field :
                    fields) {
                System.out.println(field.get(car));
            }
        }
    }
    
    • 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

    3.获取包装类的六种方式

    不同阶段不同的取包装类的方式。
    三个阶段上图有说到的:编译阶段,类加载阶段,运行阶段(有实例对象)

    上代码:

    package com.wts.reflection;
    
    import com.wts.reflection.car.Car;
    
    public class GetClass {
        public static void main(String[] args) throws ClassNotFoundException {
    
            String classAllPath = "com.wts.reflection.car.Car";
    
            //1.Class.forName   程序编译阶段
            Class<?> cls1 = Class.forName(classAllPath);
            System.out.println(cls1);
    
            //2.类名.class 类加载阶段   应用场景:用于参数传递
            Class<Car> cls2 = Car.class;
            System.out.println(cls2);
    
            //3.对象.getClass()   应用场景:有对象实例化了
            Car car = new Car();
            Class cls3 = car.getClass();
            System.out.println(cls3);
    
            //4.通过类加载器获取 类的Class对象
            //1)先得到类加载器car
            ClassLoader classLoader = car.getClass().getClassLoader();
            //2)通过类加载器得到 Class对象
            Class<?> cls4 = classLoader.loadClass(classAllPath);
            System.out.println(cls4);
    
            /*---另外两种特别的*/
            //5.基本数据类型得到Class类对象
            Class<Integer> intClass = int.class;
            System.out.println(intClass);
            Class<Boolean> booleanClass = boolean.class;
            System.out.println(booleanClass);
            //int
            //boolean
    
            //6.基本数据类型对应的包装类得到Class类对象 --5和6会自动装箱和拆箱
            Class<Integer> type = Integer.TYPE;
            System.out.println(type); //int
        }
    }
    
    
    • 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

    4. 哪些类型有Class对象

    在这里插入图片描述

    5. 类加载

    通过反射实现了类动态加载

    在这里插入图片描述

    静态加载和动态加载:

    • 静态加载:编译时加载相关的类,如果没有,则报错。
    • 动态加载:反射–>动态加载;运行时不用加载该类,(即使该类不存在),不报错(延后报错)(如下图:当输入2 后,才会报错。第一次运行不报错)
      在这里插入图片描述

    类加载的三个阶段–以及类加载后内存分布情况:
    在这里插入图片描述
    加载阶段
    在这里插入图片描述连接阶段–验证
    在这里插入图片描述连接阶段–准备
    在这里插入图片描述在这里插入图片描述

    连接阶段–解析
    在这里插入图片描述
    在这里插入图片描述其中3,保证了内存只加载一个类?(锁)

    6. 通过反射获取类的结构性息

    在这里插入图片描述

    在这里插入图片描述

    7. 通过反射创建对象

    在这里插入图片描述

    上代码:

    package com.wts.reflection;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    /*通过反射-创建实例对象*/
    public class ReflectCreateInstance {
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
    
            //1.获取Class类对象
            Class<?> aClass = Class.forName("com.wts.reflection.User");
    
            //2.通过public的无参构造器创建实例
            Object o = aClass.newInstance();
            System.out.println(o);
    
            //3.通过public的有参构造器创建实例
            /*constructor
                就是
                    public User(int age, String name) {
                    this.age = age;
                    this.name = name;
                    }
            */
            Constructor constructor = aClass.getConstructor(int.class, String.class);
            Object aaa = constructor.newInstance(66, "aaa");
            System.out.println(aaa);
    
    
            //4.通过非public的有参构造器创建实例 --暴破
            Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(int.class, String.class);
    
            declaredConstructor.setAccessible(true);//通过暴力反射可以,访问私有private构造器
            Object o4 = declaredConstructor.newInstance(100, "zhangsan");
            System.out.println(o4);
    
        }
    }
    
    /*User类*/
    class User {
        private int age = 20;
        private String name = "wts";
    
        public User() {
        }
    
        public User(int age, String name) {
            this.age = age;
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "age=" + age +
                    ", 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
    • 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

    效果:
    在这里插入图片描述

    8. 通过反射访问类中的成员

    在这里插入图片描述

    爆破反射操作类的属性

    上代码:

    package com.wts.reflection;
    
    import java.lang.reflect.Field;
    
    public class ReflectGetClassInfo {
    
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
            //1.得到Student类对应 Class对象
            Class<?> aClass = Class.forName("com.wts.reflection.Student");
    
            //2.创建对象
            Object o = aClass.newInstance();
            System.out.println(o);
    
            //3.用反射,设置age的值
            Field age = aClass.getField("age");
            age.set(o, 10);
            System.out.println(o);
            System.out.println(age.get(o));
    
            //4.用反射,设置name的值 --私有,用Declared + 爆破
            Field name = aClass.getDeclaredField("name");
            name.setAccessible(true);
            name.set(null, "aaa"); //--因为name是静态的,在类加载的时候就存在了,
    //        name.set(o,"aaa");
            System.out.println(o);
    
        }
    
    }
    
    class Student {
        public int age;
        private static String name; //--静态的,在类加载的时候就有了
    
        public Student() {
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "age=" + age
                    + "\t,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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    反射访问方法

    在这里插入图片描述
    上代码:

    package com.wts.reflection;
    
    import java.lang.reflect.Method;
    
    public class ReflectGetMethods {
        public static void main(String[] args) throws Exception {
            //1.获取类 -- 创建实例
            Class<?> aClass = Class.forName("com.wts.reflection.Boss");
            Object o = aClass.newInstance();
    
            //2.
            Method method = aClass.getMethod("hi", String.class);//带参方法
            method.invoke(o, "你好");
    
            //3.
            Method say = aClass.getDeclaredMethod("say", int.class, String.class, char.class);
            say.setAccessible(true);
            System.out.println(say.invoke(null, 20, "aaa", '男'));//--static可以 o可以取代null
    
            //4.返回值, 如果方法有返回值,统一返回Object,但是他运行类型和方法定义的返回类型一致(编译看左边运行看右边?)
            Object invoke = say.invoke(null, 500, "bbb", '女');
            System.out.println("invoke的运行类型=" + invoke.getClass());
        }
    }
    
    
    class Boss {
        public int age;
        private static String name; //--静态的,在类加载的时候就有了
    
        public Boss() {
        }
    
        private static String say(int n, String s, char c) {
            return n + " " + s + " " + c;
        }
    
        public void hi(String s) {
            System.out.println("hi" + s);
        }
    
    }
    
    • 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

    两个练习

    上代码:

    package com.wts.reflection;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    /*反射复习练习*/
    public class Reflect_review {
        public static void main(String[] args) throws Exception {
    
            /*练习1 */
    
            //1.获取Class类,创建实例
            Class<?> aClass = Class.forName("com.wts.reflection.PrivateTest");
            Object o = aClass.newInstance();
            //2.获取属性
            Field name = aClass.getDeclaredField("name");
            name.setAccessible(true);//暴力
            System.out.println(name.get(o));
            //改
            System.out.print("反射更改属性后--");
            name.set(o, "天龙八部");
            System.out.println(name.get(o));
    
            //用getname方法
            Method getName = aClass.getDeclaredMethod("getName");
            Object invoke = getName.invoke(o);
            System.out.println(invoke);
    
    
            
    
            /*练习2*/
            Class<?> fileCls = Class.forName("java.io.File");
            //指定构造器,‘文件全路径’
            Constructor<?> declaredConstructor = fileCls.getDeclaredConstructor(String.class);
            //文件的全路径
            String allPath = "E:\\桌面\\csdn钢琴家\\1_CSDN代码\\1.txt";
            Object file = declaredConstructor.newInstance(allPath);//创建file对象了 -- file的运行类型就是File
    
            //得到对象方法
            Method createNewFile = fileCls.getDeclaredMethod("createNewFile");
            createNewFile.invoke(file);
            //file的运行类型就是File
            System.out.println();
            System.out.println(file.getClass());
            System.out.println("文件创建成功" + allPath);
    
    
        }
    }
    
    class PrivateTest {
        private String name = "hellokitty";
        //默认无参构造器
    
        public String getName() {
            return 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
    • 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
  • 相关阅读:
    使用栈检查括号的合法性 C 实现
    GM8775C :是 DSI 转双通道 LVDS发送器
    哈希表搜索简介
    Python类的疑难点
    猿创征文|Java之static关键字的应用【工具类、代码块和单例】
    目标检测-SSD算法从零实现
    【数据结构初阶】八大排序(二)——快速排序&&冒泡排序
    基于 nacos/灰度发布 实现减少本地启动微服务数量的实践
    linux虚拟机查看防火墙状态
    flutter开发实战-实现自定义bottomNavigationBar样式awesome_bottom_bar
  • 原文地址:https://blog.csdn.net/Kevinwen0228/article/details/125380563