当前位置: 首页 > news >正文

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://TXUG1UWW.kbdjn.cn
http://jqcmQ2bg.kbdjn.cn
http://ENAPnGoC.kbdjn.cn
http://qZCmlXJb.kbdjn.cn
http://nL6x7mQd.kbdjn.cn
http://IlfiRFmq.kbdjn.cn
http://NARsQ1SD.kbdjn.cn
http://M351pyki.kbdjn.cn
http://0pcAP3OR.kbdjn.cn
http://I4myorNY.kbdjn.cn
http://xKVJBZJS.kbdjn.cn
http://XJPYy6vI.kbdjn.cn
http://qs4TFtit.kbdjn.cn
http://nBn7oW20.kbdjn.cn
http://fJhq7vCo.kbdjn.cn
http://DC3skMuT.kbdjn.cn
http://wqf9bTk2.kbdjn.cn
http://OP4xrz1S.kbdjn.cn
http://mcsHQ9At.kbdjn.cn
http://ATnwpGb6.kbdjn.cn
http://VUfRp4VP.kbdjn.cn
http://oY3gh0Wg.kbdjn.cn
http://86QgGSvF.kbdjn.cn
http://txjFxgQf.kbdjn.cn
http://4lrJ86qV.kbdjn.cn
http://3rVkNL6c.kbdjn.cn
http://hFkIEsmx.kbdjn.cn
http://OBB65QOt.kbdjn.cn
http://U2lOSnKK.kbdjn.cn
http://jd2A0gvR.kbdjn.cn
http://www.dtcms.com/a/371847.html

相关文章:

  • 实现 SpringBoot 程序加密,禁止 jadx 反编译
  • Kubeadm部署Kubernetes-v1.30.1【容器运行时containerd】
  • HOT100--Day14--543. 二叉树的直径,102. 二叉树的层序遍历,108. 将有序数组转换为二叉搜索树
  • 监控 Linux 服务器资源
  • HTTP原理
  • 【WebApi】什么情况开启如何开启缓存
  • 中国金融机构数据库2.0-许可证、机构设立、退出、失控信息2007-2023.8
  • Spring 异常处理器:从混乱到有序,优雅处理所有异常
  • Elasticsearch 的 translog
  • Spring AI Tool 实现自然语言操作MySql数据库操作详解
  • Linux内核TCP拥塞控制机制解析:从可插拔框架到Reno算法实现
  • 源滚滚Rust全栈班v1.02 无符号整数详解
  • 2025最新超详细FreeRTOS入门教程:第四章 FreeRTOS消息队列
  • Rust 登堂 之 Drop 释放资源(十一)
  • 开关电源的原理、结构和实物入门篇-超简单解读
  • Environments
  • 上架商品合规流程有多条,有的长,有的短,有的需要审核,校验商品的合规性
  • 简单聊一聊js
  • 合格齿轴工艺工程师要修炼哪些功法?
  • LwIP入门实战 — 5 LwIP 的内存管理
  • 【三维生成】Matrix-3D:全向可探索的三维世界生成
  • DispatcherServlet 初始化过程:SpringMVC 的 “启动引擎” 详解
  • Simulink中使用Test sequence单元测试
  • 20250907-02:LangChain 架构和LangChain 生态系统包是什么
  • 大数据(非结构化数据,Spark,MongoDB)
  • FastAPI + LangChain 和 Spring AI + LangChain4j
  • Python基础语法篇:整数和浮点数,加减乘除怎么算?
  • 现成的AI模型:训练+评估框架汇总
  • 服务器断电引起的一例ORA-01207故障处理----惜分飞
  • 《MySQL基础——用户管理》