Java动态代理、反射

文章目录

  • 动态代理
    • 调用者--->代理--->对象
    • 为什么需要代理
    • 代理的详细实现过程
    • 代码详情
  • 反射
    • 反射概念
    • 反射中常用的方法
    • 所有代码

动态代理

调用者—>代理—>对象

动态代理就是无侵入式的给代码增加新的功能,通过接口保证后面的对象和代理需要实现同一个接口,接口中就是被代理的所有方法,代理里面就是对象要被代理的方法。

为什么需要代理

因为一个对象觉得自己身上的功能太多,就会将一部分功能代理出去,对象中什么方法想要被代理,在代理中必须有对应的方法,一般会定义一个接口,接口中的方法是想要被代理的方法

代理的详细实现过程

首先是有一个需要被代理的对象,然后这个对象中有哪个方法想要被代理,创建一个接口,接口中的方法就是这个对象想要被代理的方法,在这个对象中需要实现这个接口,然后重写这几个方法。这时候就需要一个代理类,这个代理类,这个代理类主要是用到里面的代理方法,这个方法的作用是给一个对象创建一个代理,将需要被代理的对象传入其中,然后返回的是代理的对象。在这个方法里面,需要调用一个方法,就是java.util.reflect.Proxy类里面的一个方法,由于这个方法是静态方法,所以可以直接使用类名进行调用,public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)在这个方法中,第一个参数是指定哪一个类加载器去加载生成的代理类,第二个参数是指定的接口,第三个参数是用于指定生成的代理对象要干什么,一般创建代理对象不会调用到第三个参数,后面只有通过代理对象进行方法回调的时候才会调用第三个参数,在执行这个第三个参数时,会重写invoke方法进行代理方法的实现,传入invoke方法有三个参数,第一个参数是传入代理的对象,第二个参数是传入需要运行的就是原本对象的方法,第三个参数就是传入这个方法的参数。在返回的时候,返回的是传入这个方法的invoke方法传回的值。

代码详情

  • 首先是定义一个方法,里面是所有的功能,这里定义了一个明星类
public class BigStar implements Star {
    private String name;

    public BigStar() {

    }

    public BigStar(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String sing(String name) {
        System.out.println(this.name + "正在唱" + name);
        return "谢谢";
    }

    @Override
    public void dance() {
        System.out.println(this.name + "跳舞");
    }
}


  • 其次是一个需要代理的方法
/**
 * 我们可以将所有想要被代理的方法定义在接口当中
 */
public interface Star {

    // 唱歌
    String sing(String name);

    // 跳舞
    void dance();
}


  • 然后是一个代理类
public class ProxyUtil {
    /**
     * 这个方法的作用:给明星的一个对象创建一个代理
     * @param bigStar 被代理的明星对象
     * @return 给明星创建的代理
     */
    public static Star createProxy(BigStar bigStar){

        /**
         * java.util.reflect.Proxy类:提供了为对象产生代理对象的方法
         * public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
         * 参数一:用于指定用哪个类加载器去加载生成的代理类
         * 参数二:指定接口,就是这个接口用于指定生成的代理有哪些方法
         * 参数三:用于指定生成的代理对象要干什么
         */
        Star star = (Star) Proxy.newProxyInstance(
                ProxyUtil.class.getClassLoader(),
                new Class[]{Star.class},
                new InvocationHandler() {
                    @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("准备场地");
                        }
                        return method.invoke(bigStar, args);
                    }
                }
        );

        return star;
    }
}


  • 测试代理
public class Test {
    public static void main(String[] args) {

        BigStar bigStar = new BigStar("坤哥");
        Star prosy = ProxyUtil.createProxy(bigStar);
        String res = prosy.sing("鸡你太美");
        System.out.println(res);
//        ProxyUtil.createProxy(bigStar).dance();
    }
}

反射

反射概念

反射就是可以在运行时分析类和执行类的能力,通过反射可以获得任意一个类的属性和方法,还可以调用这些类的属性和方法。比如下面这张图片。

在这里插入图片描述

反射中常用的方法

在反射中,我们可以使用三种方式调用类的字节码文件,分别是Class.forName(全类名),类名.class,对象.getClass();在这三种调用类的字节码的过程中,第一种一般市用在类加载过程中的,第二种经常作为参数进行调用,第三种一般是创建对象之后,然后使用对象名进行调用。当我们获取到类的字节码文件之后,就可以通过类的字节码文件去调用类中的构造方法,成员变量和成员方法以及他们相应的信息。构造方法(Constructor),使用getConstructors可以获取到所有的公共的构造方法,使用getDeclaredConstructors可以获取所有的构造方法,使用不加s的可以用来获取单个的构造方法,但是需要传入构造方法中传入的参数类型,比如Stirng就需要传入String.class,int就需要传入int.classDeclared是用来控制是否查找公共方法,当我们获取到某个对象之后,可以使用getModifiers获取修饰这个对象的权限修饰符(但是一般获取到的都是数字比如下图),使用getParameters获取这个对象中所有传入参数的类型,然后使用newInstance去构造这个对象,但是一般private修饰的方法会报错,需要使用setAccessible(true)消除掉当前方法的修饰权限。

在这里插入图片描述

在这里插入图片描述

反射虽然给与了我们在运行时分析类和操作类的能力,但是也增加了安全性问题,可以通过setAccessible(true)方法设置对象可被强制访问,可以破坏单例的封装性

所有代码

  • 获取类字节码文件
/**
 * Java反射
 * 反射允许对类的成员变量,成员方法,构造方法的信息进行编程访问
 * 可以获取到这三者的权限修饰符,名字,返回值类型。可以对获取到的属性赋值,或者获取已经有的值。
 * 可以获取到成员方法返回的值,还可以获取到方法抛出的异常,方法上的注解
 * 可以运行获取出来的方法
 *
 * 首先要获取.class字节码文件
 * 获取class对象的三种方式:
 * 1. Class.forName("全类名");  <源代码阶段使用>
 * 2. 类名.class   <类加载阶段使用>
 * 3. 对象.getClass();    <运行阶段使用>
 */
public class ReflectDemo1 {
    public static void main(String[] args) throws ClassNotFoundException {
        Student student = new Student();

        // 最常见的一种
        System.out.println(Class.forName("oop.reflectdemo.reflect.Student"));

        // 一般当作参数进行传递
        System.out.println(Student.class);

        // 当只有这个类的对象才可以使用
        System.out.println(student.getClass());
    }
}

  • 获取类中的构造方法,属性,以及成员方法信息
/**
 * Java反射
 * 常见的获取构造方法,成员变量,成员方法的方法
 * Java中Constructor描述构造方法,Field描述成员变量,Method描述成员方法
 */
public class ReflectDemo2 {
    public static void main(String[] args) throws Exception {

        // 获取字节码文件对象
        Class clazz = Class.forName("oop.reflectdemo.reflect.Student");

        // 获取所有公共的的构造方法
        Constructor[] constructor = clazz.getConstructors();
        for (Constructor constructor1 : constructor) {
            System.out.println(constructor1);
        }

        // 获取所有的构造方法
        Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }

        /**
         * 获取单个构造方法
         * 后面括号里面需输入这个构造方法的传入值类型
         * 一般getConstructor只能获取到public修饰的方法,而要获取到所有权限修饰的方法必须用getDeclaredConstructor;
         *
         */
        clazz.getConstructor(); // 获取无参构造

        clazz.getConstructor(String.class); // 获取传入参数为String类型的构造方法

        Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class);// 获取传入参数为int的构造方法

        // 获取修饰这个对象的权限修饰符
        int modifiers = declaredConstructor.getModifiers();
        System.out.println(modifiers);

        // 获取这个对象中所有传入参数的类型
        declaredConstructor.getParameters();

        declaredConstructor.setAccessible(true);
        Student tom = (Student) declaredConstructor.newInstance("Tom", 21);
        System.out.println(tom);


        /**
         * 操作成员变量
         */
        // 获取public修饰的所有的成员变量
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        // 获取所有成员变量
        Field[] declaredField = clazz.getDeclaredFields();
        for (Field field : declaredField) {
            System.out.println(field);
        }


        // 返回单个的成员变量对象
        Field name = clazz.getDeclaredField("name");
        System.out.println(name);
        // 获取权限修饰符
        int modifiers1 = name.getModifiers();
        System.out.println(modifiers1);

        // 获取名字
        String name1 = name.getName();
        System.out.println(name1);

        // 获取类型
        Class<?> type = name.getType();
        System.out.println(type);

        // 获取成员变量记录的值
        Student s = new Student("Tom", 32);
        name.setAccessible(true);
        Object value = name.get(s);
        System.out.println(value);

        // 修改对象里面的值
        name.set(s,"Jerry");
        System.out.println(s.getName());


        /**
         * 操作成员方法
         */
        // 获取所有的公共方法
        Method[] methods = clazz.getMethods();

        // 获取所有的方法
        Method[] declaredMethods = clazz.getDeclaredMethods();

        /**
         * 获取方法进行调用
         */
        // 获取单个方法, 传入方法名,后面跟着方法传入的参数类型
        Method eat = clazz.getMethod("eat", String.class);

        // 获取方法的权限修饰符
        int modifiers2 = eat.getModifiers();

        // 获取方法的形参
        Parameter[] parameters = eat.getParameters();

        // 获取方法抛出的异常
        Class<?>[] exceptionTypes = eat.getExceptionTypes();

        // 方法运行
        Student student = new Student();
        eat.setAccessible(true);
        eat.invoke(student,"汉堡");


    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

常用的电参数

电参数根据电流的特点可以分为直流电参数和交流电参数&#xff0c;在电参数中有些是可以通过电参数表测得&#xff0c;有些参数则为通过测得的参数计算而来。 一、电参数 1.1 直接可测电参数 ——瞬时电压值 ——瞬时电流值 n——采样点数 f——频率 time——时间 其中&…

探究Java spring中jdk代理和cglib代理!

面对新鲜事物&#xff0c;我们要先了解在去探索事物的本质-默 目录 一.介绍二者代理模式 1.1.Jdk代理模式 1.2cglib代理模式 1.3二者区别 1.3.1有无接口 1.3.2灵活性 1.4对于两种代理模式的总结 1.4.1jdk代理模式 1.4.2cglib代理模式 二.两种代理模式应用场景 2.1jd…

使用R语言绘制折线图

写在前面 昨天我们分享了使用Python绘制折线图的教程,跟着NC学作图 | 使用python绘制折线图,考虑到很多同学基本不使用Python绘图。那么,我们也使用R语言复现此图形。 此外,在前期的教程中,我们基本没有分享过折线图的教程。因此,我们在这里也制作一期关于折线图的教程。…

Qt 编译使用Bit7z库接口调用7z.dll、7-Zip.dll解压压缩常用Zip、ISO9660、Wim、Esd、7z等格式文件(一)

bit7z一个c静态库&#xff0c;为7-zip共享库提供了一个干净简单的接口 使用CMAKE重新编译github上的bit7z库&#xff0c;用来解压/预览iso9660&#xff0c;WIm&#xff0c;Zip,Rar等常用的压缩文件格式。z-zip库支持大多数压缩文件格式 导读 编译bit7z(C版本)使用mscv 2017编译…

系统架构设计师之缓存技术:Redis持久化的两种方式-RDB和AOF

系统架构设计师之缓存技术&#xff1a;Redis持久化的两种方式-RDB和AOF

无人机空管电台-中大型无人机远程VHF语音电台系统

方案背景 中大型无人机在执行飞行任务时&#xff0c;特别是在管制空域飞行时地面航管人员需要通过语音与无人机通信。按《无人驾驶航空器飞行管理暂行条例》规定&#xff0c;中大型无人机应当进行适航管理。物流无人机和载人eVTOL都将进行适航管理&#xff0c;所以无人机也要有…

Spring Cloud Alibaba笔记

&#x1f600;&#x1f600;&#x1f600;创作不易&#xff0c;各位看官点赞收藏. 文章目录 Spring Cloud Alibaba 笔记1、Nacos 服务注册和配置中心1.1、Nacos 之下载启动1.2、Nacos 之注册中心1.3、Nacos 之服务发现1.4、Nacos 之配置中心1.5、Nacos 之分类配置1.6、Nacos 之…

信号处理--基于EEG脑电信号的眼睛状态的分析

本实验为生物信息学专题设计小项目。项目目的是通过提供的14导联EEG 脑电信号&#xff0c;实现对于人体睁眼和闭眼两个状态的数据分类分析。每个脑电信号的时长大约为117秒。 目录 加载相关的库函数 读取脑电信号数据并查看数据的属性 绘制脑电多通道连接矩阵 绘制两类数据…

sdk manager (ubuntu20.4) 安装

1、首先下载sdk manager 1.9.3 下载链接 https://www.baidu.com/link?urlVXJhUqxxhS3eFK3bOPTzi5LFl6ybeW3JwDY1CwANaPf1gvO3IxQKzY547NIe53x1blJxnAXg7FTRTvs-cnfnVa&wd&eqida22baa7b0004ca980000000664e2d426 当然要登录自己的账号才能成功下载&#xff0c;下载对应…

神经网络基础-神经网络补充概念-54-softmax回归

概念 Softmax回归&#xff08;Softmax Regression&#xff09;是一种用于多分类任务的机器学习算法&#xff0c;特别是在神经网络中常用于输出层来进行分类。它是Logistic回归在多分类问题上的推广。 原理 Softmax回归的主要思想是将原始的线性分数&#xff08;得分&#xf…

k8s-dashboard使用指导手册

一、访问 dashboard http://172.66.209.101:32001 二、选择 Namespace 如下图&#xff1a; 1 在①搜索框中输入 spms 2 在②选择 spms-cloud 三、查找 pod 1 打开 pod 列表 2 打开过滤窗口 3 搜索 pod 在打开的搜索框中输入 pod的关键字&#xff0c;支持模糊搜索 如搜索…

以创新点亮前路,戴尔科技开辟数实融合新格局

编辑&#xff1a;阿冒 设计&#xff1a;沐由 2023年&#xff0c;对于戴尔科技而言是特殊的一年&#xff0c;这是戴尔科技进入中国市场第25个年头——“巧合”的是&#xff0c;这25年也是中国产业经济发展最快&#xff0c;人们工作与生活发生变化最大的四分之一个世纪。 2023年&…

QT-Mysql数据库图形化接口

QT sql mysqloper.h qsqlrelationaltablemodelview.h /************************************************************************* 接口描述&#xff1a;Mysql数据库图形化接口 拟制&#xff1a; 接口版本&#xff1a;V1.0 时间&#xff1a;20230727 说明&#xff1a;支…

LION AI 大模型落地,首搭星纪元 ES

自新能源汽车蓬勃发展以来&#xff0c;随着潮流不断进步和变革的“四大件”有着明显变化。其中有&#xff1a;平台、智能驾驶、配置、以及车机。方方面面都有着不同程度的革新。 而车机方面&#xff0c;从以前老旧的媒体机、 CD 机发展至如今具有拓展性、开放性、智能化的车机…

【xxl-job快速入门搭建】

目录标题 xxl-job快速入门搭建源码地址项目结构初始化数据库启动项目1、启动服务端2、启动任务执行器端 MD文档指导教程功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内…

RISC-V公测平台发布 · 数据库在RISC-V服务器上的适配评估

前言 上一期讲到YCSB在RISC-V服务器上对MySQL进行性能测试&#xff08;RISC-V公测平台发布 使用YCSB测试SG2042上的MySQL性能&#xff09;&#xff0c;在这一期文章中&#xff0c;我们继续深入讨论RISC-V数据库的应用。本期就继续利用HS-2平台来测试数据库软件在RISC-V服务器…

神经网络为什么可以学习

本资料转载于B站up主&#xff1a;大模型成长之路,仅用于学习和讨论&#xff0c;如有侵权请联系 动画解析神经网络为什么可以学习_哔哩哔哩_bilibilis 1、一个神经网络是由很多神经元形成的 1.1 也可以是一层&#xff0c;也可以是多层 2 层和层之间的连接就跟一张网一样 2.1 每…

python35种绘图函数总结,3D、统计、流场,实用性拉满

文章目录 基础图误差线三维图等高线图场图统计图非结构坐标图 基础图 下面这8种图像一般只有两组坐标&#xff0c;直观容易理解。 函数坐标参数图形类别plotx,y曲线图stackplotx,y散点图stemx,y茎叶图scatterx,y散点图polarx,y极坐标图stepx,y步阶图barx,y条形图barhx,y横向条…

excel导入导出百万级数据优化

背景 在我前年找实习的时候&#xff0c;遇到了面试官问我&#xff1a;mysql从excel导出百万级数据&#xff0c;该怎么做&#xff1f;我听到的第一反应是&#xff1a;我*&#xff0c;我哪去接触百万级的数据&#xff0c;你们导出的数据是什么&#xff1f;我还是一个才找实习工作…

python实战【外星人入侵】游戏并改编为【梅西vsC罗】(球迷整活)——搭建环境、源码、读取最高分及生成可执行的.exe文件

文章目录 &#x1f3a5;前言&#x1f4bc;安装Pygame&#x1f50b;游戏的实现读写并存储【外星人入侵】游戏最高分游戏源码alien_invasion.pygame_functions.pyship.pyalien.pybullet.pybutton.pyscoreboard.pygame_stats.pysettings.py宇宙飞船和外星人的 .bmp类型文件 &#…