27-动态代理和反射

news2025/1/12 15:44:59

参考视频链接
反射黑马教程

反射

反射初识

反射允许对封装类的字段,方法和构造函数的信息进行编程访问
它可以将一个类里面的方法和成员变量获取出来
image.png

image.png

反射是通过 class 文件中获取这字段,构造方法和成员方法,然后在从这三个当中进行解剖,获取更多的信息。

反射获取

获取 class 对象

获取 class 对象的三种方式

  1. Class. ForName (“全类名”); (全类名就是包名加类名)
  2. 类名. Class
  3. 对象.getClass ();
    三个阶段, 分别对应三种获取 class 的方法
    image.png
    举例
        Class cl1 = Class.forName("Metamorphosis.day6.Reflect.GetClass1.Student");
        System.out.println(cl1);
        // 第二种方法
        Class cl2 = Student.class;
        System.out.println(cl2);
        // 第三种方法
        Class cl3 = new Student().getClass();
        System.out.println(cl3);

        System.out.println(cl1 == cl2);
        System.out.println(cl2 == cl3);

总结
第一种方式是最为常用的, 第二种方式我们一般是用来当作参数进行传递的, 第三种方式只有当我们已经有了这个类的对象之后, 才可以使用.

获取构造方法

image.png

public class ReflectDemo2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        //1.获得整体(class字节码文件对象)
        Class clazz = Class.forName("Metamorphosis.day6.Reflect.GetClass1.Student");


        //2.获取构造方法对象
        //获取所有构造方法(public)
        Constructor[] constructors1 = clazz.getConstructors();
        for (Constructor constructor : constructors1) {
            System.out.println(constructor);
        }

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

        //获取所有构造(带私有的)
        Constructor[] constructors2 = clazz.getDeclaredConstructors();

        for (Constructor constructor : constructors2) {
            System.out.println(constructor);
        }
        System.out.println("=======================");

        //获取指定的空参构造
        Constructor con1 = clazz.getConstructor();
        System.out.println(con1);

        Constructor con2 = clazz.getConstructor(String.class,int.class);
        System.out.println(con2);

        System.out.println("=======================");
        //获取指定的构造(所有构造都可以获取到,包括public包括private)
        Constructor con3 = clazz.getDeclaredConstructor();
        System.out.println(con3);
        //了解 System.out.println(con3 == con1);
        //每一次获取构造方法对象的时候,都会新new一个。

        Constructor con4 = clazz.getDeclaredConstructor(String.class);
        System.out.println(con4);
    }
}

获取成员变量

规则:
get表示获取
Declared表示私有
最后的s表示所有,复数形式
如果当前获取到的是私有的,必须要临时修改访问权限,否则无法使用
常用方法

方法名说明
Field[] getFields()返回所有成员变量对象的数组(只能拿 public 的)
Field[] getDeclaredFields()返回所有成员变量对象的数组,存在就能拿到
Field getField(String name)返回单个成员变量对象(只能拿public的)
Field getDeclaredField(String name)返回单个成员变量对象,存在就能拿到
public class ReflectDemo4 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        //获取成员变量对象

        //1.获取class对象
        Class clazz = Class.forName("Metamorphosis.day6.Reflect.GetClass1.Student");

        //2.获取成员变量的对象(Field对象)只能获取public修饰的
        Field[] fields1 = clazz.getFields();
        for (Field field : fields1) {
            System.out.println(field);
        }

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

        //获取成员变量的对象(public + private)
        Field[] fields2 = clazz.getDeclaredFields();
        for (Field field : fields2) {
            System.out.println(field);
        }

        System.out.println("===============================");
        //获得单个成员变量对象
        //如果获取的属性是不存在的,那么会报异常
        //Field field3 = clazz.getField("aaa");
        //System.out.println(field3);//NoSuchFieldException

        Field field4 = clazz.getField("gender");
        System.out.println(field4);

        System.out.println("===============================");
        //获取单个成员变量(私有)
        Field field5 = clazz.getDeclaredField("name");
        System.out.println(field5);

    }
}

获取成员变量并获取值和修改值

方法说明
void set(Object obj, Object value)赋值
Object get(Object obj)获取值
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        Student s = new Student("zhangsan",23,"广州");
        Student ss = new Student("lisi",24,"北京");

        //需求:
        //利用反射获取成员变量并获取值和修改值

        //1.获取class对象
        Class clazz = Class.forName("Metamorphosis.day6.Reflect.GetClass1.Student");

        //2.获取name成员变量
        //field就表示name这个属性的对象
        Field field = clazz.getDeclaredField("name");
        //临时修饰他的访问权限
        field.setAccessible(true);

        //3.设置(修改)name的值
        //参数一:表示要修改哪个对象的name?
        //参数二:表示要修改为多少?
        field.set(s,"wangwu");

        //3.获取name的值
        //表示我要获取这个对象的name的值
        String result = (String)field.get(s);

        //4.打印结果
        System.out.println(result);

        System.out.println(s);
        System.out.println(ss);

    }

获取成员方法

常用方法

方法名说明
Method[] getMethods()返回所有成员方法对象的数组(只能拿public的)
Method[] getDeclaredMethods()返回所有成员方法对象的数组,存在就能拿到
Method getMethod(String name, Class<?>… parameterTypes)返回单个成员方法对象(只能拿public的)
Method getDeclaredMethod(String name, Class<?>… parameterTypes)返回单个成员方法对象,存在就能拿到
        //1.获取class对象
        Class<?> clazz = Class.forName("Metamorphosis.day6.Reflect.GetClass1.Student");


        //2.获取方法
        //getMethods可以获取父类中public修饰的方法
        Method[] methods1 = clazz.getMethods();
        for (Method method : methods1) {
            System.out.println(method);
        }

        System.out.println("===========================");
        //获取所有的方法(包含私有)
        //但是只能获取自己类中的方法
        Method[] methods2 = clazz.getDeclaredMethods();
        for (Method method : methods2) {
            System.out.println(method);
        }

        System.out.println("===========================");
        //获取指定的方法(空参)
        Method method3 = clazz.getMethod("sleep");
        System.out.println(method3);

        Method method4 = clazz.getMethod("eat",String.class);
        System.out.println(method4);

        //获取指定的私有方法
        Method method5 = clazz.getDeclaredMethod("playGame");
        System.out.println(method5);

获取成员方法并运行

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //1.获取字节码文件对象
        Class clazz = Class.forName("com.itheima.a02reflectdemo1.Student");
		
        //2.获取一个对象
        //需要用这个对象去调用方法
        Student s = new Student();
        
        //3.获取一个指定的方法
        //参数一:方法名
        //参数二:参数列表,如果没有可以不写
        Method eatMethod = clazz.getMethod("eat",String.class);
        
        //运行
        //参数一:表示方法的调用对象
        //参数二:方法在运行时需要的实际参数
        //注意点:如果方法有返回值,那么需要接收invoke的结果
        //如果方法没有返回值,则不需要接收
        String result = (String) eatMethod.invoke(s, "重庆小面");
        System.out.println(result);

    }

动态代理

代理的初步认识

平常我们修改代码的时候我们一般是进行侵入式修改, 也就是直接修改源代码
当我们既不想修改修改源代码, 可是又想要增加额外的功能, 这种情况下我们就可以使用这个动态代理.
程序为什么需要代理, 代理它长什么样

  1. 如果对象认为自己身上的事情太多的话, 我们就可以通过代理来转移部分的职责
  2. 代理里面并不能够实现某些功能, 但是它可以通过调用可以实现这功能的对象函数的代码来实现这个功能.
  3. 对象有什么方法想被代理, 代理里就一定要有对应的方法
  4. 我们通过这个接口来实现这个代理, 想要代理什么方法, 就要把这个方法写在这个接口当中
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如何为 java 对象创建一个代理呢

Java. Long. Reflect. Proxy 类中提供了为对象产生代理对象的方法
image.png
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InnovationHandler h

举例

明星对象 (我省略了 setter 和 getter 方法)

public class Star implements daili {
    private String name;
    @Override
    public String sing(String name) {
        System.out.println(this.name + " 正在演唱 " + name);
        return "谢谢";
    }
    @Override
    public String dance() {
        System.out.println(this.name + " 正在跳舞");
        return "谢谢";
    }
}

代理 (这是一个接口, 包含了明星对象的几个功能代码)

public interface daili {
    public abstract String sing(String name);
    public abstract String dance();
}

Proxy 类

public class ProxyTest {
    public static daili createProxy(Star star) {
        daili starDaili = (daili) Proxy.newProxyInstance(
                ProxyTest.class.getClassLoader(), // 参数一:指定用哪个类加载器,去加载生成的类
                new Class[] { daili.class }, // 参数二:指定接口,这些接口用于指定代理是什么样的,也就是有哪些方法
                // 参数三,用于指定这个代理做什么事情.
                new InvocationHandler() {
                    /**
                     * 参数一: 代理的对象
                     * 参数二: 要运行的方法sing
                     * 参数三: 调用sing方法的时候传递的实参
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if ("sing".equals(method.getName())) {
                            System.out.println("准备场地,收钱可以开始唱歌了");
                        } else if ("dance".equals(method.getName())) {
                            System.out.println("准备场地,收钱可以开始跳舞了");
                        }
                        // 之后这个代理,去找这个明星类中的唱歌和跳舞的方法,这里需要利用反射的知识
                        method.invoke(star, args);
                        return "谢谢";
                    }
                });
        return starDaili;
    }
}

测试代码

public class Test {

    /**
     * 如果想要让这个明星唱歌:
     * 我们首先要找到这个代理
     * ProxyTest.createProxy(Star star);
     * 然后通过这个代理去执行这个唱歌的方法
     * 代理对象.唱歌("鸡你太美") //也就是我们的第三个参数
     */
    public static void main(String[] args) {
        Star star = new Star("坤哥");
        daili createProxy = ProxyTest.createProxy(star);
        String result = createProxy.sing("鸡你太美");
        System.out.println(result);
        createProxy.dance();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1056848.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【LeetCode热题100】--148.排序链表

148.排序链表 对链表进行排序最适合的算法就是归并排序&#xff1a; 对链表自顶向下归并排序的过程&#xff1a; 找到链表的中点&#xff0c;以中点为分界&#xff0c;将链表拆分成两个子链表&#xff0c;寻找链表的中点可以使用快慢指针的做法&#xff0c;快指针每次移动 2步…

c++三大概念要分清--重载,隐藏(重定义),覆盖(重写)

目 录 一、重载 **&#xff08;1&#xff09;概念&#xff1a;**在同一个作用域内&#xff1b;函数名相同&#xff0c;参数列表不同&#xff08;参数个数不同&#xff0c;或者参数类型不同&#xff0c;或者参数个数和参数类型都不同&#xff09;&#xff0c;返回值类型可相同也…

leetCode 122.买卖股票的最佳时机 II 贪心算法

122. 买卖股票的最佳时机 II - 力扣&#xff08;LeetCode&#xff09; 给你一个整数数组 prices &#xff0c;其中 prices[i] 表示某支股票第 i 天的价格。 在每一天&#xff0c;你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买&…

【mysql】—— 复合查询

前言&#xff1a; 在前面我已经讲解的mysql表的查询都是对一张表进行查询&#xff0c;在实际开发中这远远不够。因此&#xff0c;本期我将带大家学习的是关于 “ 复合查询” 的相关知识&#xff01;&#xff01;&#xff01; 目录 &#xff08;一&#xff09;基本查询回顾 &a…

解决mac pro 连接4k显示器严重发烫、卡顿问题

介绍个不用花钱的方法。其实mac自带的风扇散热能力还可以的&#xff0c;但是默认比较懒散&#xff0c;可以用一个软件来控制下&#xff0c;激发下它的潜能。 可以下个stats软件 打开传感器开关&#xff0c;以及同步控制风扇开关 以及cpu显示温度 点击控制台上的温度图标&…

MySQL 面试题——数据库理论基础

目录 1.什么是数据库、数据库管理系统、数据库系统、数据库管理员&#xff1f;2.什么是元组、码、候选码、主码、外码、主属性、非主属性&#xff1f;3.什么是 ER 图&#xff1f;它有哪几个要素组成&#xff1f;4.主键与外键有什么区别&#xff1f;5.✨为什么不推荐使用外键与级…

简单走近ChatGPT

目录 一、ChatGPT整体背景认知 &#xff08;一&#xff09;ChatGPT引起关注的原因 &#xff08;二&#xff09;与其他公司的竞争情况 二、NLP学习范式的发展 &#xff08;一&#xff09;规则和机器学习时期 &#xff08;二&#xff09;基于神经网络的监督学习时期 &…

深入浅出剖析 LoRA 源码及实践

在上一篇中&#xff0c;我们详细阐述了LoRA的原理。在本篇中&#xff0c;我们将一起学习LoRA源码&#xff08;微软原版&#xff09;。 许多朋友在使用LoRA的过程中&#xff0c;都会用到HuggingFace Peft库封装好的LoRA接口&#xff0c;这个接口是对微软版LoRA代码的改写和封装…

全国核辐射检测数据月度表

特别说明 吸收剂量是单位质量受照物质所吸收的平均电离辐射能量&#xff0c;单位是J/kg。 专门名词是戈瑞&#xff08;Gray&#xff09;&#xff0c;符号“Gy”&#xff0c;1Gy 1J/kg。 这是个很大的单位。 因此在实际应用时&#xff0c;往往用其千分之一或百万分之一作单位&a…

【Java 进阶篇】使用 JDBC 更新数据详解

在关系型数据库中&#xff0c;更新数据是一项常见的任务。通过Java JDBC&#xff08;Java Database Connectivity&#xff09;&#xff0c;我们可以使用Java编程语言来执行更新操作&#xff0c;例如修改、删除或插入数据。本文将详细介绍如何使用JDBC来进行数据更新操作&#x…

《XSS-Labs》01. Level 1~10

XSS-Labs 索引Level-1题解 Level-2题解 Level-3题解总结 Level-4题解 Level-5题解总结 Level-6题解 Level-7题解 Level-8题解 Level-9题解 Level-10题解 靶场部署在 VMware - Win7。 靶场地址&#xff1a;https://github.com/do0dl3/xss-labs 只要手动注入恶意 JavaScript 脚本…

多目标平衡优化器黏菌算法(MOEOSMA)求解CEC2020多模式多目标优化

多目标平衡优化器黏菌算法&#xff08;MOEOSMA&#xff09;比现有的多目标黏菌算法具有更好的优化性能。在MOEOSMA中&#xff0c;动态系数用于调整勘探和开采趋势。采用精英存档机制来促进算法的收敛性。使用拥挤距离法来保持Pareto前沿的分布。采用平衡池策略模拟黏菌的协同觅…

开放式耳机怎么选择、300之内最好的耳机推荐

开放式耳机凭借不入耳、不伤耳、安全更舒适的佩戴体验&#xff0c;得到了越来越多音乐爱好者和专业人士的青睐。开放式耳机不需要插入耳道&#xff0c;在佩戴时可以更加自然和轻松&#xff0c;减少了长时间佩戴引起的不适感&#xff0c;而且不会完全隔绝外界声音&#xff0c;用…

手机号码格式校验:@PhoneQuery(作为查询参数)(自定义参数校验注解)

目标 自定义一个用于校验&#xff08;作为查询参数的&#xff09;手机号码格式的注解PhoneQuery&#xff0c;能够和现有的 Validation 兼容&#xff0c;使用方式和其他校验注解保持一致。 校验逻辑 可以为 null 或 空字符串&#xff1b;不能包含空格&#xff1b;必须为数字序…

Mysql主从复制数据架构全面解读

大家好&#xff0c;我是山子&#xff0c;今天给大家分析Mysql 实现主从复制的方方面面&#xff0c;主从复制当然也是我们做读写分离的前提&#xff0c;以下内容是从各网络平台摘录整理总结归纳在一起的&#xff1b;内容已经从主从复制的各方面的维度进行了阐述&#xff1b;非常…

百元价位开放式耳机哪款好、百元耳机性价比最高的开放式耳机推荐

现如今越来越多的人选择开放式耳机&#xff0c;因为开放式耳机具有多重优点&#xff0c;首先是舒适性。由于它们不需要插入耳道&#xff0c;长时间佩戴也不会产生不适感。其次&#xff0c;开放式耳机在保持与外界的连接上表现出色&#xff0c;使得户外活动更加安全。另外&#…

【Spring Cloud】基于 Feign 实现远程调用,深入探索 Feign 的自定义配置、性能优化以及最佳实践方案

前言 在微服务架构中&#xff0c;服务之间的通信是至关重要的&#xff0c;而远程调用则成为实现这种通信的一种常见方式。在 Java 中&#xff0c;使用 RestTemplate 是一种传统的远程调用方式&#xff0c;但它存在一些问题&#xff0c;如代码可读性差、编程体验不一致以及参数…

笔记二:odoo搜索、筛选和分组

一、搜索 1、xml代码 <!--搜索和筛选--><record id"view_search_book_message" model"ir.ui.view"><field name"name">book_message</field><field name"model">book_message</field><field…

愚蠢的代码?某程序员强行编写了一段开发阶段无法调试的代码,大佬们快来救救他!

文章目录 一、开场白1. 程序员打赌的故事2. 目标&#xff1a; 尽量在不修改代码的情况下将springmvc框架以独立jar方式运行 二、出师不利方案一、Spring Web工程转Spring Boot方案二、引入内置服务器jetty其余备用方案 三、柳暗花明遇见jetty-runner测试验证准备工作:部署工作 …

基于web的画作展示系统/作品展示平台

摘 要 网络的广泛应用给生活带来了十分的便利。所以把画作展示系统与现在网络相结合&#xff0c;利用JSP技术建设画作展示系统&#xff0c;实现画作展示系统的信息化。则对于进一步提高画作展示系统的发展&#xff0c;丰富画作展示系统经验能起到不少的促进作用。 画作展示系统…