• Java基础-反射


    代理相关

    为什么需要代理?

    代理可以无侵入式的对方法进行增强,而不需要修改原始方法的代码,这样就可以在不修改原始方法的情况下,对方法进行增强。

    代理长什么样子?

    代理里面就是对象要被代理的方法

    Java通过什么方式来保证代理的样子?

    通过接口保证,后面的对象和代理需要实现同一个接口,接口中就是被代理的所有方法

    代码演示:

    1. BigStar.java
    public class BigStar implements Star {
        private String name;
    
        @Override
        public String sing(String name) {
            System.out.println(this.name + "正在唱" + name);
            return name;
        }
    
        @Override
        public void dance() {
            System.out.println(this.name + "正在跳舞");
        }
        //...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    1. Star接口
    public interface Star {
        //把需要被代理的方法定义在接口中
        String sing(String name);
    
        void dance();
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. 代理工具
    
    public class ProxyUtil {
        /**
         * 作用:给一个明星对象创建代理
         * 形参:被代理的明星对象
         * 返回值:给明星创建的代理
         * 

    * 需求:外面的人需要大明星唱一首歌 */ public static Star createProxy(BigStar bigStar) { Star star = (Star) Proxy.newProxyInstance( ProxyUtil.class.getClassLoader(), //参数一:类加载器 new Class[]{Star.class}, //参数二:被代理类的所有接口 //参数三:代理对象的调用处理程序 new InvocationHandler() { @Override public Object invoke(Object o, Method method, Object[] args) throws Throwable { /* 参数一:代理对象 参数二:被代理的方法 参数三:被代理方法的参数 */ if ("sing".equals(method.getName())) { System.out.println("准备话筒,收钱"); } else if ("dance".equals(method.getName())) { System.out.println("准备舞台,收钱"); } //执行被代理的方法 //返回被代理方法的返回值 return method.invoke(bigStar, args); } } ); return star; } }

    • 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
    1. 测试类
    public class Test {
        public static void main(String[] args) {
            BigStar star = new BigStar("蔡徐坤");
            Star proxy = ProxyUtil.createProxy(star);
            String result = proxy.sing("只因你太美");
            System.out.println(result);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    反射

    什么是反射?

    反射允许对成员变量,成员方法和构造方法的信息进行编程访问

    获取反射三种方式

    public class Test {
        public static void main(String[] args) throws Exception {
            //第一种方式:
            //最为常用的方式,通过类的全路径,获取Class对象
            Class clazz = Class.forName("com.cxk.fanshe.Student");
    
            //第二种方式,更多的是当作参数传递
            Class clazz2 = Student.class;
    
            //第三种方式
            //当我们已经有了这个类的对象,才可以使用
            Student student = new Student();
            Class clazz3 = student.getClass();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    反射获取构造方法

    Declared表示私有

    方法名说明
    Constructor[] getConstructors()获得所有的构造(只能public修饰)
    Constructor[] getDeclaredConstructors()获得所有的构造(包含private修饰)
    Constructor getConstructor(Class… parameterTypes)获取指定构造(只能public修饰)
    Constructor getDeclaredConstructor(Class… parameterTypes)获取指定构造(包含private修饰)

    Demo

    public class Test {
        public static void main(String[] args) throws Exception {
            //1.获取class字节码文件对象
            Class<?> clazz = Class.forName("com.cxk.fanshe.Student");
            //2.1获取所有的构造方法
            Constructor[] con1 = clazz.getDeclaredConstructors();
            for (Constructor constructor : con1) System.out.println(constructor);
    
            //2.2获取指定的构造方法
            Constructor con2 = clazz.getDeclaredConstructor(); //空参
            Constructor con3 = clazz.getDeclaredConstructor(String.class, Integer.class); //有参
    
            int modifiers = con3.getModifiers();        //获取权限修饰符
            Parameter[] parameters = con3.getParameters();//获取参数列表
    
            con3.setAccessible(true);//暴力反射 无视权限修饰符 这样就可以访问私有构造方法了
            Student cxk =(Student) con3.newInstance("cxk", 23);//创建对象
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    获取成员变量

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

    Demo:

    public class Test {
        public static void main(String[] args) throws Exception {
            //1.获取class字节码文件对象
            Class clazz = Class.forName("com.cxk.fanshe.Student");
    
            Field[] fields = clazz.getDeclaredFields();//获取成员变量 所有的
            Field age = clazz.getDeclaredField("age");//获取单个的
            int modifiers = age.getModifiers();//获取权限修饰符
            Class type = age.getType();//获取数据类型
            String name = age.getName();//获取变量名
            Student cxk = new Student("cxk", 30);
    
            age.setAccessible(true);//暴力反射
            Integer value =(Integer) age.get(cxk);
            System.out.println(value);
            age.set(cxk, 18);//修改已记录的值
            System.out.println(cxk);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    获取成员方法

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

    Demo:

    public class Test {
        public static void main(String[] args) throws Exception {
            //1.获取class字节码文件对象
            Class clazz = Class.forName("com.cxk.fanshe.Student");
    
            Method[] methods1 = clazz.getMethods(); //获取所有的方法(包括父类)
            Method[] methods = clazz.getDeclaredMethods();//获取所有的方法(不能获取父类)
    
            Method eat = clazz.getMethod("eat", String.class);//获取单一方法
            int modifiers = eat.getModifiers();//获取方法的修饰符
            String name = eat.getName();//获取方法的名称
            int parameterCount = eat.getParameterCount();//获取方法的参数个数
            Class returnType = eat.getReturnType();//获取方法的返回值类型
            Parameter[] parameters = eat.getParameters();//获取方法的参数列表
            Class[] parameterTypes = eat.getParameterTypes();//获取方法的参数类型列表
    
            Student cxk = new Student("cxk", 30);
            eat.setAccessible(true);//暴力反射 使私有方法可以被访问
            String apple =(String) eat.invoke(cxk, "apple");//执行方法
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    利用反射保存对象信息

    Demo:

    public class Test {
        public static void main(String[] args) throws  Exception {
        /*
            对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去
        */
            Student s = new Student("小A",23,'女',167.5,"睡觉");
            Teacher t = new Teacher("播妞",10000);
            saveObject(s);
            saveObject(t);
        }
    
        //把对象里面所有的成员变量名和值保存到本地文件中
        public static void saveObject(Object obj) throws  Exception {
            //1.获取字节码文件的对象
            Class clazz = obj.getClass();
            //2. 创建IO流
            BufferedWriter bw = new BufferedWriter(new FileWriter("./a.txt"));
            //3. 获取所有的成员变量
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                //获取成员变量的名字
                String name = field.getName();
                //获取成员变量的值
                Object value = field.get(obj);
                //写出数据
                bw.write(name + "=" + value);
                bw.newLine();
            }
    
            bw.close();
    
        }
    }
    
    • 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

    学生类:

    public class Student {
        private String name;
        private int age;
        private char gender;
        private double height;
        private String hobby;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    教师类:

    public class Teacher {
        private String name;
        private double salary;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    StarGAN v2: Diverse Image Synthesis for Multiple Domains (多域多样性图像合成)
    判断动物知识竞猜答案正误
    下载huggingface预训练模型到本地并调用
    Oracle Primavera Unifier Version 22.10 新特征
    Langchain中使用Ollama提供的Qwen大模型进行Function Call实现天气查询、网络搜索
    前端导出数据到Excel(Excel.js导出数据)
    leetCode 76. 最小覆盖子串 + 滑动窗口 + 哈希Hash
    Vue复刻华为官网 (一)
    javaweb——socket
    C语言暑假学习刷题——Day8
  • 原文地址:https://blog.csdn.net/m0_74085417/article/details/134045509