【JavaSE】Java中的反射动态代理

本篇文章整理的内容来源于: 反射原理

文章目录

  • 一. 动态代理
    • 1. 优点
    • 2. 动态代理三要素
    • 3. 创建代理对象并使用
  • 二. 反射
    • 1. 什么是反射
    • 2. 获取字节码文件对象的三种方式
      • (1) Class.forName()获取 (源代码阶段)
      • (2) 通过class属性获取
      • (3) 通过对象获取字节码文件对象
    • 3. 获取构造方法
    • 4. 获取构造方法并创建对象
      • (1)获取空参,并创建对象.
      • (2)获取带参构造,并创建对象
    • 5. 获取成员变量
    • 6. 获取成员方法
    • 7. 反射的作用

一. 动态代理

1. 优点

使用动态代理能够无侵入式的给方法增强功能.

所谓无侵入式,指的是在原有代码的基础上,不需要修改原始类的源代码,就可以通过代理来增强其功能。通过动态代理,我们可以在代理对象的方法执行前后插入额外的逻辑,例如日志记录、性能监测、事务管理等。这样可以在不修改原始类的情况下,通过代理对象对方法进行增强,达到扩展功能的目的。

动态代理利用了反射机制,在运行时动态地生成代理类和代理对象,从而实现对原始对象的包装。通过调用代理对象的方法,实际上是调用了被代理对象的方法,并在方法执行前后执行额外的逻辑。

2. 动态代理三要素

  1. 真正执行任务的对象.
  2. 代理对象
  3. 利用代理调用方法

在这里插入图片描述

3. 创建代理对象并使用

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

我们可以使用java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

参数一:用于指定用哪个类加载器,去加载生成的代理类
参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
参数三:用来指定生成的代理对象要干什么事情

package com.xxxflower.demo1;
public class BigStar implements Star {private String name;public BigStar() {}public BigStar(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 + "正在跳舞");}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}public String toString() {return "BigStar{name = " + name + "}";}
}
package com.xxxflower.demo1;
public interface Star {//我们可以把所有想要被代理的方法定义在接口当中//唱歌public abstract String sing(String name);//跳舞public abstract void dance();
}
package com.xxxflower.demo1;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** 类的作用:*       创建一个代理** */
public class ProxyUtil {/*** 方法的作用:*       给一个明星的对象,创建一个代理**  形参:*       被代理的明星对象**  返回值:*       给明星创建的代理**** 需求:*   外面的人想要大明星唱一首歌*   1. 获取代理的对象*      代理对象 = ProxyUtil.createProxy(大明星的对象);*   2. 再调用代理的唱歌方法*      代理对象.唱歌的方法("只因你太美");* */public static Star createProxy(BigStar bigStar){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 {/** 参数一:代理的对象* 参数二:要运行的方法 sing* 参数三:调用sing方法时,传递的实参* */if("sing".equals(method.getName())){System.out.println("准备话筒,收钱");}else if("dance".equals(method.getName())){System.out.println("准备场地,收钱");}//去找大明星开始唱歌或者跳舞//代码的表现形式:调用大明星里面唱歌或者跳舞的方法return method.invoke(bigStar,args);}});return star;}
}
package com.xxxflower.demo1;public class Test {public static void main(String[] args) {/*需求:外面的人想要大明星唱一首歌1. 获取代理的对象代理对象 = ProxyUtil.createProxy(大明星的对象);2. 再调用代理的唱歌方法代理对象.唱歌的方法("只因你太美");*///1. 获取代理的对象BigStar bigStar = new BigStar("鸡哥");Star proxy = ProxyUtil.createProxy(bigStar);//2. 调用唱歌的方法String result = proxy.sing("只因你太美");System.out.println(result);}
}

在这里插入图片描述
程序执行结果:
在这里插入图片描述

二. 反射

1. 什么是反射

Java中的反射(Reflection),是指在运行时动态地获取类的信息,以及动态地调用对象的方法和属性。简而言之,就是程序在运行时可以动态地获取类的信息并对其进行操作

Java反射机制允许程序在运行时检查和操作类、接口、字段、方法以及构造方法等元素,例如:

  1. 获取类的名称、修饰符、父类、实现的接口等信息。
  2. 动态地创建对象,即使不知道具体类的名称。
  3. 获取或设置字段的值,即使它们是私有的。
  4. 调用对象的方法,即使不知道方法的名称或参数列表。
  5. 获取或设置方法的注解信息等。

反射机制为Java编程提供了更大的灵活性和扩展性,尤其在框架设计、动态代理、JavaBean操作等方面得到广泛应用。但是由于反射会牺牲一定的性能,因此在性能要求较高的场景下,应该谨慎使用反射。

2. 获取字节码文件对象的三种方式

反射都是从class字节码文件中获取的内容。因此如果我们想使用反射,就必须首先获取class字节码文件的对象.
获取字节码文件对象的三种方式如下

(1) Class.forName()获取 (源代码阶段)

我们可以通过Class这个类里面的静态方法forName(“全类名”)来获取.示例:
注意: 全类名 = 包名 + 类名

Class clazz1 = Class.forName("com.xxxflower.reflectdemo.Student");

源代码阶段获取 — > 先把Student加载到内存中,再获取字节码文件的对象
clazz 就表示Student这个类的字节码文件对象。即Student.class这个文件加载到内存之后,产生的字节码文件对象.

(2) 通过class属性获取

通过 类名.class 示例如下:

Class clazz2 = Student.class;

class文件在硬盘中是唯一的.
所以,当这个文件加载到内存之后产生的对象也是唯一的.

(3) 通过对象获取字节码文件对象

示例:

Student s = new Student();
Class clazz3 = s.getClass();

此处注意几个概念:
字节码文件:通过.java文件编译之后的.class文件(真实存在的)
字节码文件对象:当.class文件加载到内存之后,虚拟机自动创建出来的对象.这个对象里面至少包含了:构造方法,成员变量,成员方法。

我们反射所获取的就是字节码文件对象.

3. 获取构造方法

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

代码示例:

public class ReflectDemo2 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {//1.获得整体(class字节码文件对象)Class clazz = Class.forName("com.itheima.reflectdemo.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);}
}

4. 获取构造方法并创建对象

(1)获取空参,并创建对象.

示例:

//1.获取整体的字节码文件对象
Class clazz = Class.forName("com.itheima.a02reflectdemo1.Student");
//2.获取空参的构造方法
Constructor con = clazz.getConstructor();
//3.利用空参构造方法创建对象
Student stu = (Student) con.newInstance();
System.out.println(stu);

(2)获取带参构造,并创建对象

示例:

//1.获取整体的字节码文件对象
Class clazz = Class.forName("com.itheima.a02reflectdemo1.Student");
//2.获取有参构造方法
Constructor con = clazz.getDeclaredConstructor(String.class, int.class);
//3.临时修改构造方法的访问权限(暴力反射)
con.setAccessible(true);
//4.直接创建对象
Student stu = (Student) con.newInstance("zhangsan", 23);
System.out.println(stu);

5. 获取成员变量

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

6. 获取成员方法

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

7. 反射的作用

  1. 获取任意一个类中的所有信息
  2. 结合配置文件动态创建对象

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

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

相关文章

LeetCode刷题11:滑动窗口解决1423.可获得的最大点数

几张卡牌 排成一行&#xff0c;每张卡牌都有一个对应的点数。点数由整数数组 cardPoints 给出。 每次行动&#xff0c;你可以从行的开头或者末尾拿一张卡牌&#xff0c;最终你必须正好拿 k 张卡牌。 你的点数就是你拿到手中的所有卡牌的点数之和。 给你一个整数数组 cardPoi…

网页设计与制作web前端设计html+css+js成品。电脑网站制作代开发。vscodeDrea 【企业公司宣传网站(HTML静态网页项目实战)附源码】

网页设计与制作web前端设计htmlcssjs成品。电脑网站制作代开发。vscodeDrea 【企业公司宣传网站&#xff08;HTML静态网页项目实战&#xff09;附源码】 https://www.bilibili.com/video/BV1Hp4y1o7RY/?share_sourcecopy_web&vd_sourced43766e8ddfffd1f1a1165a3e72d7605

c语言:用指针找出第一个相同的元素|练习题

一、题目 用指针&#xff0c;找出两数组中第一个相同的元素&#xff0c;并输入该元素 如图&#xff1a; 二、代码截图【带注释】 三、源代码【带注释】 #include <stdio.h> void f(); int main() { int a[5] {5,6,7,8,9}; int b[5] {6,4,6,8,3}; int *pa; …

工智能基础知识总结--什么是TextCNN

什么是TextCNN Yoon Kim在论文(2014 EMNLP) Convolutional Neural Networks for Sentence Classification提出TextCNN&#xff0c;该模型将卷积神经网络CNN应用到文本分类任务&#xff0c;是卷积神经网络应用到文本分析的开创性工作之⼀。 TextCNN的结构 TextCNN的结构图如下&…

【详解】静态库和动态库的认识和使用【Linux】

静态库和动态库的认识和使用 静态库和动态库的概述动静态库的实现静态库动态库库文件名称和引入库的名称 静态库和动态库的概述 静态库&#xff08;.a&#xff09;&#xff1a;程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库 动态库&#…

Spring Boot 基础知识点1 (含面试题1)

Spring Boot 是一款基于 Spring 框架的开源应用程序开发工具&#xff0c;它旨在简化 Spring 应用程序的配置和开发过程。Spring Boot 提供了一种简单的方式来创建可独立运行的、生产级别的应用程序&#xff0c;并在需要时进行部署。Spring Boot 在微服务架构和云计算环境下得到…

报错curl: (6) Could not resolve host: raw.githubusercontent...的解决办法

我起初想要在macOS系统安装pip包&#xff0c;首先在终端安装homebrew&#xff0c;敲了命令&#xff1a;/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent...)" 之后触发的报错&#xff0c;报错内容&#xff1a;curl: (6) Could not resolve host: raw.…

2024.1.7每日一题

LeetCode 383.赎金信 383. 赎金信 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你两个字符串&#xff1a;ransomNote 和 magazine &#xff0c;判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以&#xff0c;返回 true &#xff1b;否则返回 false 。…

Python count()方法:统计字符串出现的次数与字符串拼接(包含字符串拼接数字)

Python count()方法&#xff1a;统计字符串出现的次数 count 方法用于检索指定字符串在另一字符串中出现的次数&#xff0c;如果检索的字符串不存在&#xff0c;则返回 0&#xff0c;否则返回出现的次数。 count 方法的语法格式如下&#xff1a; str.count(sub[,start[,end]]…

Ranger UserSync

作用 同步User到RangerDb 架构 解析 启动一个while(True) 进程定时同步&#xff0c;程序入口 source sink 掉接口获取Ranger User 并且Cache 计算delta 同步

如何编写高效的正则表达式?

正则表达式&#xff08;Regular Expression&#xff0c;简称regex&#xff09;是一种强大的文本处理技术&#xff0c;广泛应用于各种编程语言和工具中。本文将从多个方面介绍正则表达式的原理、应用和实践&#xff0c;帮助你掌握这一关键技术。 正则可视化 | 一个覆盖广泛主题…

元数据管理平台对比预研 Atlas VS Datahub VS Openmetadata

大家好&#xff0c;我是独孤风。元数据管理平台层出不穷&#xff0c;但目前主流的还是Atlas、Datahub、Openmetadata三家&#xff0c;那么我们该如何选择呢&#xff1f; 本文就带大家对比一下,这三个平台优势劣势。要了解元数据管理平台&#xff0c;先要从架构说起。 正文共&am…