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;}@Overridepublic String sing(String name) {System.out.println(this.name + "正在唱" + name);return "谢谢";}@Overridepublic 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() {@Overridepublic 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,"汉堡");}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

19万字智慧城市总体规划与设计方案WORD

导读&#xff1a;原文《19万字智慧城市总体规划与设计方案WORD》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 感知基础设施 感知基础设施架构由感知范围、感知手…

Excel/PowerPoint折线图从Y轴开始(两侧不留空隙)

默认Excel/PowerPoint折线图是这个样子的&#xff1a; 左右两侧都留了大块空白&#xff0c;很难看 解决方案 点击横坐标&#xff0c;双击&#xff0c;然后按下图顺序点击 效果

No mapping found for HTTP request with URI

参考: 参考地址 说明 ssm老项目,接过来别人的项目 临时建了一个Controller方便测试用的,结果访问掉不通,报: No mapping found for HTTP request with URIxxxx 这样的错误 解决办法 看了下web,xml配置 在 webmvc-config.xml 配置文件里面添加了几行配置 说明: com.iph.h…

实景无人直播平台是这么开发出来的

标题&#xff1a;实景无人直播平台开发&#xff1a;探索专业性、思考深度与逻辑性的全新体验 随着科技的不断进步&#xff0c;实景无人直播平台成为了当今数字娱乐领域的热门话题。这种新型娱乐方式将虚拟与现实相结合&#xff0c;为用户带来了前所未有的视听体验。本文将探…

搜狗拼音占用了VSCode及微信小程序开发者工具快捷键Ctrl + Shit + K 搜狗拼音截图快捷键

修改搜狗拼音的快捷键 右键--更多设置--属性设置--按键--系统功能快捷键--系统功能快捷键设置--取消Ctrl Shit K的勾选--勾选截屏并设置为Ctrl Shit A 微信开发者工具设置快捷键 右键--Command Palette--删除行 微信开发者工具快捷键 删除行&#xff1a;Ctrl Shit K 或…

【LeetCode】复写零

复写零 题目描述算法描述编程代码 链接: 复写零 题目描述 算法描述 编程代码 class Solution { public:void duplicateZeros(vector<int>& arr) {int n arr.size();int dest -1,cur 0;while(cur < n){if(arr[cur]){dest;}else{dest2;}cur;if(dest > n-1){…

数学建模大全及优缺点解读

分类模型 1、距离聚类&#xff08;系统聚类&#xff09;&#xff08;常用&#xff0c;需掌握&#xff09; 优点&#xff1a; ①将一批样本数据按照他们在性质上的亲密程度在没有先验知识的情况下自动进行分类 ②是一种探索性的分析方法&#xff0c;分类结果不一定相同 例如&am…

java面试基础 -- 深克隆 浅克隆

引例 说到java的克隆你还记得多少? 一说到克隆你可能就会想起来那个接口, 没错, 他就是Cloneable Cloneable是java里面内置的很常用的接口, 我们说 Object类中也有一个clone方法: 但是要想合法调用 clone 方法, 必须要先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedEx…

Redis 数据库 NoSQL

目录 一、NoSQL 二、为什么会出现NoSQL技术 三、NoSQL的类别 键值&#xff08;Key-Value&#xff09;存储数据库 列存储数据库 文档型数据库 图形&#xff08;Graph&#xff09;数据库 四、NoSQL适应场景 五、在分布式数据库中CAP原理 1、CAP 2、BASE 一、NoSQL NoS…

[C++ 网络协议编程] 域名及网络地址

1. DNS服务器 DNS&#xff08;Domain Name System&#xff09;&#xff1a;是对IP地址和域名&#xff08;如:www.baidu.com等&#xff09;进行相互转换的系统&#xff0c;其核心是DNS服务器。 我们输入的www.baidu.com是域名&#xff0c;是一种虚拟地址&#xff0c;而非实际地…

Error creating bean with name ‘esUtils‘ defined in file

报错异常&#xff1a; 背景&#xff1a; esUtils在common服务中、启动media服务时候、报这个异常、后排查esUtils在启动时候发生异常引起的、在相关bean中加入try{}catch{}即可解决问题 String[] split url.split(","); HttpHost[] httpHosts new HttpHost[split.…

MySQL的配置文件my.cnf与my.ini

一、my.cnf与my.ini win系统&#xff0c;MySQL配置文件为my.ini 其他系统&#xff08;Ubuntu、CentOS、macOS)MySQL配置文件为my.cnf 二、my.cnf与my.ini的路径 2.1 默认路径 MySQL 的配置文件 my.cnf 可能位于多个位置&#xff0c;具体取决于安装方式和操作系统。以下是一…

燃尽图、甘特图、鱼骨图

燃尽图、甘特图、鱼骨图 1. 燃尽图 燃尽图&#xff08;burn down chart&#xff09;是在项目完成之前&#xff0c;对需要完成的工作的一种可视化表示。燃尽图有一个Y轴&#xff08;工作&#xff09;和X轴&#xff08;时间&#xff09;。理想情况下&#xff0c;该图表是一个向下…

2023.8 - java - Number类和Math类

一般地&#xff0c;当需要使用数字的时候&#xff0c;我们通常使用内置数据类型&#xff0c;如&#xff1a;byte、int、long、double 等。 然而&#xff0c;在实际开发过程中&#xff0c;我们经常会遇到需要使用对象&#xff0c;而不是内置数据类型的情形。为了解决这个问题&a…

LeetCode[面试题04.12]求和路径

难度&#xff1a;Medium 题目&#xff1a; 给定一棵二叉树&#xff0c;其中每个节点都含有一个整数数值(该值或正或负)。设计一个算法&#xff0c;打印节点数值总和等于某个给定值的所有路径的数量。注意&#xff0c;路径不一定非得从二叉树的根节点或叶节点开始或结束&#x…

Java数据库连接池原理及spring boot使用数据库连接池(HikariCP、Druid)

和线程池类似&#xff0c;数据库连接池的作用是建立一些和数据库的连接供需要连接数据库的业务使用&#xff0c;避免了每次和数据库建立、销毁连接的性能消耗&#xff0c;通过设置连接池参数可以防止建立连接过多导致服务宕机等&#xff0c;以下介绍Java中主要使用的几种数据库…

nlp系列(7)三元组识别(Bi-LSTM+CRF)pytorch

模型介绍 在实体识别中&#xff1a;使用了Bert模型&#xff0c;CRF模型 在关系识别中&#xff1a;使用了Bert模型的输出与实体掩码&#xff0c;进行一系列变化&#xff0c;得到关系 Bert模型介绍可以查看这篇文章&#xff1a;nlp系列&#xff08;2&#xff09;文本分类&…

神经网络简单理解:机场登机

目录 神经网络简单理解&#xff1a;机场登机 ​编辑 激活函数&#xff1a;转为非线性问题 ​编辑 激活函数ReLU 通过神经元升维&#xff08;神经元数量&#xff09;&#xff1a;提升线性转化能力 通过增加隐藏层&#xff1a;增加非线性转化能力​编辑 模型越大&#xff0c;…

网络安全---负载均衡案例

一、首先环境配置 1.上传文件并解压 2.进入目录下 为了方便解释&#xff0c;我们只用两个节点&#xff0c;启动之后&#xff0c;大家可以看到有 3 个容器&#xff08;可想像成有 3 台服务器就成&#xff09;。 二、使用蚁剑去连接 因为两台节点都在相同的位置存在 ant.jsp&…

leetcode349. 两个数组的交集

简单题&#xff0c;竟然想了20分钟 题目 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 示例 1&#xff1a; 输入&#xff1a;nums1 [1,2,2,1], nums2 [2,2] 输出&#xff…