Java反射与动态代理学习笔记

Java 反射与动态代理学习笔记

反射概述

反射允许对成员变量、成员方法和构造方法进行编程访问,提供了在运行时分析类和对象的能力。

获取Class对象的三种方式

方式代码示例说明
Class.forName()Class.forName("全类名")通过类的全限定名获取Class对象
对象.getClass()对象.getClass()通过对象实例获取Class对象
类名.class类名.class通过类字面常量获取Class对象
// 1. Class.forName("全类名")
Class clazz1 = Class.forName("com.zzz.Student");
System.out.println(clazz1);// 2. 对象.getClass()
ReflectionDemo reflectionDemo = new ReflectionDemo();
Class clazz2 = reflectionDemo.getClass();// 3. 类名.class
Class clazz3 = ReflectionDemo.class;// 三种方式获取的Class对象是相同的
System.out.println(clazz1 == clazz2); // true
System.out.println(clazz1 == clazz3); // true

反射操作构造方法

Class类中获取构造方法的方法

方法说明
Constructor<?>[] getConstructors()返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors()返回所有构造方法对象的数组
Constructor<T> getConstructor(Class<?>... parameterTypes)返回单个公共构造方法对象
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)返回单个构造方法对象

Constructor类中创建对象的方法

方法说明
T newInstance(Object... initargs)根据指定的构造方法创建对象
setAccessible(boolean flag)设置为true,表示取消访问检查
// 获取所有公共构造方法
Constructor[] constructors = clazz1.getConstructors();
for (Constructor c : constructors) {System.out.println(c);
}
// 输出:
// public com.zzz.Student()
// public com.zzz.Student(java.lang.String,int)// 获取所有构造方法(包括私有和受保护的)
Constructor[] allConstructors = clazz1.getDeclaredConstructors();
for (Constructor c : allConstructors) {System.out.println(c);
}
// 输出:
// public com.zzz.Student()
// private com.zzz.Student(int)
// protected com.zzz.Student(java.lang.String)
// public com.zzz.Student(java.lang.String,int)// 获取特定构造方法
Constructor constructor = clazz1.getConstructor(String.class, int.class);
System.out.println(constructor); // public com.zzz.Student(java.lang.String,int)// 获取私有构造方法
Constructor privateConstructor = clazz1.getDeclaredConstructor(int.class);
System.out.println(privateConstructor);// 使用构造方法创建对象
constructor.setAccessible(true); // 临时取消权限校验
Student stu = (Student) constructor.newInstance("张三", 18);
System.out.println(stu);

反射操作成员变量

Class类中获取成员变量的方法

方法说明
Field[] getFields()返回所有公共成员变量对象的数组
Field[] getDeclaredFields()返回所有成员变量对象的数组
Field getField(String name)返回单个公共成员变量对象
Field getDeclaredField(String name)返回单个成员变量对象

Field类中操作成员变量的方法

方法说明
void set(Object obj, Object value)给指定对象的字段赋值
Object get(Object obj)获取指定对象的字段值
String getName()获取字段名称
Class<?> getType()获取字段类型
int getModifiers()获取字段修饰符
// 获取所有公共成员变量
Field[] publicFields = clazz1.getFields();
for (Field f : publicFields) {System.out.println(f);
}
// 输出: public java.lang.String com.zzz.Student.gender// 获取所有成员变量(包括私有)
Field[] allFields = clazz1.getDeclaredFields();
for (Field f : allFields) {System.out.println(f);
}
// 输出:
// private java.lang.String com.zzz.Student.name
// private int com.zzz.Student.age
// public java.lang.String com.zzz.Student.gender// 获取特定成员变量
Field ageField = clazz1.getDeclaredField("age");
System.out.println(ageField); // private int com.zzz.Student.age// 获取成员变量信息
String fieldName = ageField.getName();
System.out.println(fieldName); // ageClass fieldType = ageField.getType();
System.out.println(fieldType); // intint modifiers = ageField.getModifiers();
System.out.println(modifiers); // 2 (表示private)// 获取和设置字段值
Student student = new Student("张三", 18, "男");
ageField.setAccessible(true); // 访问私有字段需要取消访问检查
int ageValue = (int) ageField.get(student);
System.out.println(ageValue); // 18// 修改字段值
ageField.set(student, 19);
System.out.println(student); // Student{name='张三', age=19, gender='男'}

反射操作成员方法

Class类中获取成员方法的方法

方法说明
Method[] getMethods()返回所有公共成员方法对象的数组(包括父类方法)
Method[] getDeclaredMethods()返回所有成员方法对象的数组(仅本类方法)
Method getMethod(String name, Class<?>... parameterTypes)返回单个公共成员方法对象
Method getDeclaredMethod(String name, Class<?>... parameterTypes)返回单个成员方法对象

Method类中调用方法的方法

方法说明
Object invoke(Object obj, Object... args)调用方法
String getName()获取方法名称
Class<?> getReturnType()获取方法返回值类型
Class<?>[] getParameterTypes()获取方法参数类型数组
Class<?>[] getExceptionTypes()获取方法异常类型数组
int getModifiers()获取方法修饰符
// 获取所有公共方法(包括父类方法)
Method[] publicMethods = clazz1.getMethods();
for (Method m : publicMethods) {System.out.println(m);
}// 获取所有方法(仅本类方法)
Method[] allMethods = clazz1.getDeclaredMethods();
for (Method m : allMethods) {System.out.println(m);
}// 获取特定方法
Method sleepMethod = clazz1.getMethod("sleep");
System.out.println(sleepMethod);// 获取带参数的方法
Method eatMethod = clazz1.getDeclaredMethod("eat", String.class);
System.out.println(eatMethod);// 获取方法信息
int methodModifiers = eatMethod.getModifiers();
System.out.println(methodModifiers);String methodName = eatMethod.getName();
System.out.println(methodName); // eatClass returnType = eatMethod.getReturnType();
System.out.println(returnType); // class java.lang.StringClass[] parameterTypes = eatMethod.getParameterTypes();
for (Class c : parameterTypes) {System.out.println(c); // class java.lang.String
}Class[] exceptionTypes = eatMethod.getExceptionTypes();
for (Class c : exceptionTypes) {System.out.println(c); // class java.io.IOException, class java.lang.ClassNotFoundException
}// 调用方法
Student student = new Student("张三", 18, "男");
eatMethod.setAccessible(true); // 访问私有方法需要取消访问检查
Object result = eatMethod.invoke(student, "西风");
System.out.println(result); // 吃奥里给
import java.io.IOException;public class Student {private String name;private int age;public String gender;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}protected Student(String name) {this.name = name;}private Student(int age) {this.age = age;}public Student(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;}// Getter和Setter方法public String getName() { return name; }public void setName(String name) { this.name = name; }public int getAge() { return age; }public void setAge(int age) { this.age = age; }public String getGender() { return gender; }public void setGender(String gender) { this.gender = gender; }@Overridepublic String toString() {return "Student{name='" + name + "', age=" + age + ", gender='" + gender + "'}";}public void sleep() {System.out.println("睡觉");}private String eat(String something) throws IOException, ClassNotFoundException {System.out.println("吃" + something);return "吃奥里给";}
}

反射与配置文件结合

利用反射与配置文件结合的方式,可以动态创建对象并调用方法,提高代码的灵活性。

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {// 1. 读取配置文件Properties properties = new Properties();FileInputStream fis = new FileInputStream("day27-Reflection\\src\\prop.properties");properties.load(fis);fis.close();System.out.println(properties);// 2. 获取全类名和方法名String methodName = properties.getProperty("method");String className = properties.getProperty("className");System.out.println(className);System.out.println(methodName);// 3. 利用反射创建对象Class clazz = Class.forName(className);Constructor constructor = clazz.getConstructor();Object obj = constructor.newInstance();System.out.println(obj);// 4. 获取并调用方法Method method = clazz.getDeclaredMethod(methodName);method.setAccessible(true);method.invoke(obj);}
}

配置文件示例(prop.properties):

className=com.zzz.demo.Student
method=study

动态代理

动态代理可以在运行时创建代理对象,对方法调用进行拦截和处理。

代理接口

public interface Star {// 唱歌String sing();// 跳舞void dance();
}

被代理类

public class BigStar implements Star {private String name;public BigStar() {}public BigStar(String name) {this.name = name;}// 唱歌@Overridepublic String sing() {System.out.println(name + "正在唱歌");return "谢谢";}// 跳舞@Overridepublic void dance() {System.out.println(name + "正在跳舞");}// Getter和Setter省略
}

代理工具类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyUtil {/*** JDK创建代理对象* Java.lang.reflect.Proxy类中提供了为对象产生代理对象的方法* * public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)* 参数一:用于指定用哪个类加载器,去加载生成的代理类* 参数二:指定接口,这些接口用于指定生成的代理有哪些方法* 参数三:用来指定生成的代理对象要干什么事*/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 {/*** proxy 第一个参数:代理的对象* method 第二个参数:代理对象要调用的方法 sing* args 第三个参数:代理对象要调用方法时,传递的参数*/if (method.getName().equals("sing")) {System.out.println("代理开始工作,准备话筒,收钱");} else if (method.getName().equals("dance")) {System.out.println("代理开始工作,准备场地,收钱");}// 调用大明星中的唱歌或者跳舞方法Object result = method.invoke(bigStar, args);if (method.getName().equals("sing")) {System.out.println("代理工作结束(唱歌)");} else if (method.getName().equals("dance")) {System.out.println("代理工作结束(跳舞)");}return result;}});return star;}
}

测试代理

public class Test {public static void main(String[] args) {BigStar star = new BigStar("张三");Star proxy = ProxyUtil.createProxy(star);proxy.dance();// 输出:// 代理开始工作,准备场地,收钱// 张三正在跳舞// 代理工作结束(跳舞)String singResult = proxy.sing();System.out.println(singResult);// 输出:// 代理开始工作,准备话筒,收钱// 张三正在唱歌// 代理工作结束(唱歌)// 谢谢}
}

总结

反射是Java中强大的特性,它允许程序在运行时检查类、接口、字段和方法的信息,并能够动态创建对象、调用方法和访问字段。结合配置文件使用反射可以提高代码的灵活性和可扩展性。

动态代理则基于反射机制,允许在运行时创建代理对象,对方法调用进行拦截和处理,常用于AOP编程、日志记录、事务管理等场景。

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

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

相关文章

RAG提示词分解

RAG提示词分解 System Message # 智能问答助手&#xff08;RAG系统提示&#xff09;## 角色定义 您是"智能问答助手"&#xff0c;专门基于提供的上下文信息回答用户问题。## 核心规则 1. **严格基于上下文**&#xff1a;仅使用用户提供的<context>中的信息&…

YOLOv8 在 Intel Mac 上的 Anaconda 一键安装教程

YOLOv8 在 Intel Mac 上的 Anaconda 一键安装教程 本文适用于 Intel 芯片 Mac&#xff0c;通过 Anaconda 快速搭建 YOLOv8 环境&#xff0c;支持 CPU 推理与 Notebook 可视化。 全程一键安装&#xff0c;适合小白和入门用户。 &#x1f4d1; 目录 环境准备 一键安装脚本 运行…

Spring 日志文件

Spring 日志文件 文章目录Spring 日志文件日志有什么用&#xff1f;日志怎么用&#xff1f;自定义日志在程序中获取日志对象常用日志框架说明使用日志对象打印日志日志格式说明日志级别日志级别有啥用日志级别分类和使用日志持久化保存更简单的日志输出——lomboklombok更多注解…

五、误差反向传播法(上)

上一章中&#xff0c;我们介绍了神经网络的学习&#xff0c;并通过数值微分计算了神经网络的权重参数的梯度&#xff08;严格来说&#xff0c;是损失函数关于权重参数的梯度&#xff09;。数值微分虽然简单&#xff0c;也容易实现&#xff0c;但缺点是计算上比较费时间。本章我…

Rust Axum 快速上手指南(静态网页和动态网页2024版)

本文基于 Axum 0.7.5&#xff08;当前稳定版&#xff09;、tower-http 0.5.2、MiniJinja 0.7.2 编写&#xff0c;涵盖生产环境核心场景&#xff1a;tower-http Layer 叠加与数据传递、静态网页服务、MiniJinja 动态模板渲染&#xff0c;并重点解析请求 / 应答在多 Layer 中的流…

Golang语言设计理念

起源 Golang语言始于2007年&#xff0c;是一门编译型、静态类型、并发友好 的语言&#xff0c;由Robert Griesemer&#xff08; 罗伯特格里森、图灵奖获得者、C 语法联合发明人、Unix 之父&#xff09;、Rob Pike&#xff08; 罗布派克、Plan 9 操作系统领导者、UTF-8 编码的最…

深入掌握 nsenter:Linux命名空间操作的利器

#作者&#xff1a;朱雷 文章目录1、简介2、功能与用途2.1. 核心功能2.1.1. 进入命名空间2.1.2. 支持多种命名空间2.1.3. 容器调试3、安装3.1. 依赖包3.2. 权限要求3.3. 命令用法与示例3.3.1. 基本语法3.3.2. 常用选项包括&#xff1a;3.3.3. 示例4、 应用场景与优势4.1. 容器调…

Ubuntu Qt x64平台搭建 arm64 编译套件

环境&#xff1a; 主机平台&#xff1a;Ubuntu22.04.5 x86_64 目标平台&#xff1a;IMX8QM Ubuntu22.04.5 arm64 Qt版本&#xff1a;Qt6.5.3 LST GUI实现&#xff1a;QML 一、获取Ubuntu22.04.5 x86_64 系统镜像文件 1、镜像下载与安装 使用国内镜像下载对应版本的Ubuntu镜像…

mysql第五天学习 Mysql全局优化总结

Mysql全局优化总结 从上图可以看出SQL及索引的优化效果是最好的&#xff0c;而且成本最低&#xff0c;所以工作中我们要在这块花更多时间。 补充一点配置文件my.ini或my.cnf的全局参数&#xff1a; 假设服务器配置为&#xff1a; CPU&#xff1a;32核内存&#xff1a;64GDISK…

leetcode hot100 二叉搜索树

二叉搜索树的第k小的数class Solution:def kthSmallest(self, root: Optional[TreeNode], k: int) -> int:# 二叉搜索树的中序遍历是 升序排列的&#xff0c; 求第k小的&#xff0c;即第k个数self.res []def fun(root):if not root:returnfun(root.left)if root:self.res.a…

从Sonnet到Opus:一次解决RAG知识库流式输出难题的探索

又到周末&#xff0c;还得消耗消耗 ➡️ anyrouter 上的Claude资源&#xff0c;万一哪天都不能用了&#xff0c;也是浪费。 2025/9/5&#xff0c;Claude AI 的母公司 Anthropic 发布了一项新政策&#xff1a;即日起&#xff0c;Anthropic将不再对中国控股公司及其海外子公司开放…

「数据获取」中国科技统计年鉴(1991-2024)Excel

02、数据详情数据名称&#xff1a;《中国科技统计年鉴》&#xff08;1991-2024年&#xff09;数据年份&#xff1a;1991-202403、数据截图 04、获取方式&#xff08;获取方式看绑定的资源&#xff09;

SimLingo:纯视觉框架下的自动驾驶视觉 - 语言 - 动作融合模型

摘要 本文深入探讨了 SimLingo&#xff0c;一个在自动驾驶领域具有开创性意义的视觉-语言-动作一体化模型。SimLingo 创新性地将自动驾驶、语言理解和指令感知控制整合到一个统一的纯摄像头框架中&#xff0c;显著提升了自动驾驶系统在复杂环境中的感知、决策与执行能力。该模…

第五十四天(SQL注入数据类型参数格式JSONXML编码加密符号闭合复盘报告)

#SQL注入产生原理&#xff1a; 代码中执行的SQL语句存在可控变量导致 #常见SQL注入的利用过程&#xff1a; 1、判断数据库类型 2、判断参数类型及格式 3、判断数据格式及提交 4、判断数据回显及防护 5、获取数据库名&#xff0c;表名&#xff0c;列名 5、获取对应数据及…

VMWare上搭建Hive集群

文章目录1. MySQL安装2. 安装Hive集群3. 使用Hive客户端4. 实战总结本实战在VMware上搭建Hive集群&#xff0c;集成MySQL作为元数据存储&#xff0c;完成Hive环境配置、元数据初始化及HDFS仓库目录创建&#xff0c;实现Hive on Hadoop的SQL查询能力&#xff0c;为大数据分析提供…

Android网络之WIFI技术网络模型概述

文章目录术语1、WLAN与WIFI2、802.11 WIFI无线网络标准演进3、WIFI5、WIFI6和WIFI7的最高速率对比4、WIFI网络中的各个角色&#xff08;元件&#xff09;1&#xff09;网络拓扑架构图5、802.11权威指南1&#xff09;OSI与TCP/IP2&#xff09;IEEE 802.11协议簇介绍3&#xff09…

游戏中的设计模式——第三篇 简单工厂模式

5. 简单工厂模式 5.1 简单工厂模式的定义 简单工厂模式的核心是定义一个创建对象的接口&#xff0c;将对象的创建和本身的业务逻辑分离&#xff0c;降低系统的耦合度&#xff0c;使得两个修改起来相对容易些&#xff0c;当以后实现改变时&#xff0c;只需要修改工厂类即可。 5.…

基于SVN搭建企业内部知识库系统实践

一、准备工作 CentOS 7 服务器&#xff1a;确保你有 root 或 sudo 权限&#xff0c;可以访问该服务器。Windows 客户端&#xff1a;你将需要在 Windows 上安装 TortoiseSVN 客户端来与 SVN 服务器交互。防火墙&#xff1a;确保你的防火墙已开放 3690 端口&#xff0c;用于 SVN…

SQL注入7----(盲注与回显)

一.前言 在我们的注入语句被带入数据库查询但却什么都没有返回的情况我们该怎么办&#xff1f;例如应用程序就会返回 一个"通用的"的页面&#xff0c;或者重定向一个通用页面&#xff08;可能为网站首页&#xff09;。这时&#xff0c;我们之前学习的SQL注入办 法就…

尚硅谷宋红康JVM全套教程(详解java虚拟机)

https://www.bilibili.com/opus/1071553679925968898 案例7&#xff1a;日均百万订单系统JVM参数设置 https://github.com/wei198621/jvm_by_atguigu https://github.com/xftxyz2001/atguigu-jvm/blob/main/JavaYouthdocsJVM/%E7%AC%AC1%E7%AB%A0-JVM%E4%B8%8EJava%E4%BD%…