[java学习日记]反射、动态代理

目录

一.反射的简单解释与获取字节码文件对象

二.获取构造方法对象Constructor

三.反射获取字节码文件中的成员变量Field

四.反射获取字节码文件中的成员方法:Method

五.反射练习:保存信息

六.反射练习:利用配置文件(存储类名和方法名),动态创建对象并调用方法

七.动态代理


一.反射的简单解释与获取字节码文件对象

反射:允许对封装类的成员变量、构造方法、成员方法获取出来然后进行操作,或者获取到如修饰符,名字等更加详细的信息
没有反射怎么拿?使用IO流!但是比较麻烦,这里就用反射咯
1.获取Class的有哪三种方式?1.Class.forName("全类名")2.类名.class3.对象.getClass()
对应三个不同的阶段1.源代码:编译时期2.加载阶段:在内存当中的时候3.运行阶段:已经有对象了
2.这三种方法获取的是什么对象?
public class Demo351 {public static void main(String[] args) throws ClassNotFoundException {System.out.println("(1)获取Class的第一种方式:需要传入全类名的字符串:包含包名,最为常用");System.out.println("IDEA中获取:选择类名,然后右键选择copy_Reference");Class<?> class1 = Class.forName("Day35_Reflect_DynamicAgent.Demo351");System.out.println(class1);System.out.println("(2)获取Class的第二种方式,通过类名调用");System.out.println("第二种则是多用于作为参数作为传递:比如当作锁");Class<?> class2 = Demo351.class;System.out.println("(3)获取Class的第三种方式,通过对象调用,也是获取的字节码文件");//已经有对象的时候才可以使用Class<?> class3 = new Student().getClass();System.out.print("2.前两个类对象都是获取的字节码文件,是同一个对象:");System.out.println(class2==class1);}
}

学生类JavaBean,下面案例都是使用的此学生类

//四个构造方法:两个是私有的
//有个成员方法抛出了异常
public class Student {private String name;private int age;public Student() {}private Student(String name) {this.name = name;}private Student(int age) {this.age = age;}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}public void setName(String name) throws Exception{this.name = name;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}


二.获取构造方法对象Constructor

从字节码文件里面获取数据对象的内容:本类测试获取构造方法对象Constructor
1.使用什么方法获取所有公共构造方法呢?
2.使用什么方法获取所有构造方法呢(包括私有)?
3.获取单个构造方法时传入的参数应该是?
4.如何获取构造方法内的权限修饰符?
5.如何读取方法中的参数?
6.如何使用私有构造方法创建变量?
public class Demo352 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//获取字节码文件对象Class<?> studentClass = Class.forName("Day35_Reflect_DynamicAgent.Student");System.out.println("1.使getConstructors获取构造方法,获取所有公共构造方法");Constructor<?>[] constructors = studentClass.getConstructors();for (Constructor<?> constructor : constructors) System.out.println(constructor);System.out.println("2.获取所有构造方法(Declared:公开声明的)");constructors = studentClass.getDeclaredConstructors();for (Constructor<?> constructor : constructors) System.out.println(constructor);System.out.println("3.获取单个构造方法:指定构造方法可以传递参数:数据类型的字节码文件,基本数据类型也要传.class字节码文件");Constructor<?> constructor = studentClass.getConstructor();System.out.println(constructor);constructor = studentClass.getConstructor(String.class,int.class);System.out.println(constructor);constructor = studentClass.getDeclaredConstructor(int.class);System.out.println(constructor);//获取构造方法里面的内容System.out.println("4.使用getModifier方法读取权限修饰符:内容是2的整数倍(和底层运算效率有关,左右移就能改变)");//有什么用呢?写IDEA源码有用,提示能够直接看到能传上面参数System.out.println(constructor.getModifiers());System.out.println("5.使用getParameters方法读取有哪些参数");Parameter[] parameters = constructor.getParameters();for (Parameter parameter : parameters) System.out.println(parameter);System.out.println("6.使用构造方法创建对象:私有方法不能够创建对象,需要临时取消权限校验(暴力反射)");System.out.println("首先把构造方法调用setAccessible方法,传入true为参数");constructor.setAccessible(true);System.out.println("再使用构造方法的newInstance方法构造其对象");Student student = (Student) constructor.newInstance(23);System.out.println(student);}
}


三.反射获取字节码文件中的成员变量Field

反射获取字节码文件中的成员变量Field
1.获取单个变量需要传入的参数?
2.如何获取变量名?
3.如何获取变量类型?
4.如何获取对象中的变量的值?
5.如何修改对象中变量的值?
public class Demo353 {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {//获取Field也是一样的方法Class<?> studentClass = Class.forName("Day35_Reflect_DynamicAgent.Student");Field[] fields = studentClass.getDeclaredFields();for (Field field : fields) System.out.println(field);System.out.println("1.获取单个成员变量:传入变量名字符串");Field field = studentClass.getDeclaredField("age");//获取成员变量信息System.out.println(field.getModifiers());System.out.println("2.使用getName方法获取变量名");System.out.println(field.getName());System.out.println("3.使用getType方法获取变量类型");Class<?> type = field.getType();System.out.println(type);System.out.println("4.使用get方法传入某对象,获取这个成员变量在该对象中的值,同样也需要取消权限校验");field.setAccessible(true);Student student = new Student("zhangsan", 123);Object age = field.get(student);System.out.println(age);System.out.println("5.使用set方法,传入某对象与修改的值,对该对象中的成员变量修改");field.set(student,1234);System.out.println(student);}
}


四.反射获取字节码文件中的成员方法:Method

反射获取字节码文件中的成员方法:Method
1.使用getMethods方法与getDeclaredMethods方法有什么区别?
2.如何获取单个方法,传入的参数是?
3.如何返回方法抛出的异常?
4.如何使用method对某对象调用方法?传入的参数与返回的参数有什么特点?
public class Demo354 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {Class<?> studentClass = Class.forName("Day35_Reflect_DynamicAgent.Student");Method[] methods = studentClass.getMethods();System.out.println("1.使用getMethods方法同时也有继承与Object中的方法");for (Method method : methods)System.out.println(method);methods = studentClass.getDeclaredMethods();System.out.println("获取所有方法的时候不会包含继承下来的方法");for (Method method : methods)System.out.println(method);System.out.println("2.通过名字和形参获取一个方法,可以不加形参");Method method = studentClass.getMethod("setName",String.class);System.out.println(method);//修饰符,名字,参数System.out.println(method.getModifiers());System.out.println(method.getName());for (Parameter parameter : method.getParameters())System.out.println(parameter);System.out.println("3.使用getExceptionTypes返回方法抛出的异常数组");System.out.println(Arrays.toString(method.getExceptionTypes()));System.out.println("4.调用invoke(调用)方法,第一个参数传入对象,第二个参数没有就不写,方法没有返回也可以不写");Student student = new Student();method.invoke(student,"zhangsan");System.out.println(student);}
}

 


五.反射练习:保存信息

对于任意一个对象:把对象所有信息保存到文件当中,对于不同的对象都可以如此操作
public class Demo355 {final static String FILE_STR = "D:\\IDEACode\\demo1\\JAVA基础\\src\\Day35_Reflect_DynamicAgent\\message.properties";public static void main(String[] args) throws IllegalAccessException, IOException {Student student = new Student("zhansgan",123);Properties properties =new Properties();Class<?> studentClass = student.getClass();//获取字节码文件中的所有成员变量Field[] fields = studentClass.getDeclaredFields();for (Field field : fields) {//设置取消检验field.setAccessible(true);//获取变量名String name = field.getName();//获取对象中的该变量Object o = field.get(student);properties.put(name,o.toString());}properties.store(new FileWriter(FILE_STR),"addStudent");}
}


六.反射练习:利用配置文件(存储类名和方法名),动态创建对象并调用方法

public class Demo356 {final static String FILE_STR = "D:\\IDEACode\\demo1\\JAVA基础\\src\\Day35_Reflect_DynamicAgent\\prop.properties";public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Properties properties = new Properties();properties.load(new FileReader(FILE_STR));//获取字节码文件Class<?> aClass = Class.forName((properties.get("classname").toString()));//获取构造方法,创建对象Constructor<?> constructor = aClass.getConstructor();Object o = constructor.newInstance();//获取方法名并调用Method method = aClass.getMethod(properties.get("method").toString());System.out.println(method.invoke(o));}
}


七.动态代理

动态代理:不修改原有的代码,又需要增加额外功能
为了程序的健壮性,不改变原有代码的功能,使用动态代理完成一些额外的事情
想要找某个核心人物做事情,需要先找它的代理人去说要做的事情,代理人里面也要有核心任务的方法
如何确定需要代理的方法呢?
为了确定需要代理的方法,需要让核心人物与代理人都实现某一个接口

需要代理的类

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("跳舞");}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "BigStar{" +"name='" + name + '\'' +'}';}
}

需要代理的方法的接口

public interface Star {String sing(String name);void dance();
}

代理工具类 :用来创建代理对象

public class ProxyUtil {public static Star createProxy(BigStar bigStar) {System.out.println("""1.创建静态方法返回一个代理人(类型为BigStar实现的结构)方法作用:给明星对象创建一个代理形参:被代理的明星对象返回一个接口,也是返回代理对象""");System.out.println("2.使用Proxy的newProxyInstance方法创建代理人对象,传入三个参数");System.out.println("""参数一:指定类加载器加载生成的代理类:找到谁加载了这个类参数二:指定接口数组,用于指定代理能代理哪些方法参数三:指定代理要干什么事情,在这个参数需要的对象需要实现的方法参数有三个参数一:代理的对象,暂时用不到参数二:要运行的方法参数三:调用方法的时候需要传递的实参""");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 Demo361 {public static void main(String[] args) {//创建代理人Star proxy = ProxyUtil.createProxy(new BigStar("mona"));//使用代理人去调用方法System.out.println(proxy.sing("偶像宣言"));proxy.dance();}
}

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

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

相关文章

第21章:网络通信

21.1 网络程序设计基础 21.1.1 局域网与互联网 为了实现两台计算机的通信&#xff0c;必须用一个网络线路连接两台计算机。如下图所示 21.1.2 网络协议 1.IP协议 IP是Internet Protocol的简称&#xff0c;是一种网络协议。Internet 网络采用的协议是TCP/IP协议&#xff0…

Google Bard vs. ChatGPT 4.0:文献检索、文献推荐功能对比

在这篇博客中&#xff0c;我们将探讨和比较四个不同的人工智能模型——ChatGPT 3.5、ChatGPT 4.0、ChatGPT 4.0插件和Google Bard。我们将通过三个问题的测试结果来评估它们在处理特定任务时的效能和响应速度。 导航 问题 1: 统计自Vehicle Routing Problem (VRP)第一篇文章发…

netty源码:(4)ServerBootstrap

ServerBootstrap的group方法用来给成员变量赋值&#xff0c;如下图 AbstractBootstrap为ServerBootstrap的父类。 ServerBootstrap的channel方法用来设置channelFactory成员变量(在父类AbstractBootstrap里&#xff09; ServerBootstrap的childHandler方法用来给本类的成员…

软件开发的代码审查工具

在进行软件开发时&#xff0c;代码审查&#xff08;Code Review&#xff09;是一种非常重要的实践&#xff0c;它有助于发现潜在的问题、提高代码质量&#xff0c;并促使团队成员之间的知识共享。有许多工具可用于简化和优化代码审查过程。以下是一些常见的代码审查工具&#x…

【Pyqt】QObject::connect: Cannot queue arguments of type ‘QTextCursor‘

问题说明 文本框接收到新的数据 不会自动滚动&#xff0c;并提示警告 QObject::connect: Cannot queue arguments of type ‘QTextCursor’ (Make sure ‘QTextCursor’ is registered using qRegisterMetaType().) 原因 线程回来的槽函数里面 调用了ui的代码 我们不能通过线程…

ArcGIS Pro中怎么设置标注换行

在ArcGIS Pro中进行文字标注的时候&#xff0c;如果标注的字段内容太长&#xff0c;直接标注的话会不美观&#xff0c;而且还会影响旁边的标注显示&#xff0c;这里为大家介绍一下在ArcGIS Pro中设置文字换行的方法&#xff0c;希望能对你有所帮助。 数据来源 本教程所使用的…

深入浅出理解kafka ---- 万字总结

1.Kafka简介 Kafka 本质上是一个 MQ&#xff08;Message Queue&#xff09;&#xff0c;使用消息队列的优点&#xff1a; 解耦&#xff1a;允许独立的扩展或修改队列两边的处理过程。可恢复性&#xff1a;即使一个处理消息的进程挂掉&#xff0c;加入队列中的消息仍然可以在系…

【无线网络技术】——无线个域网(学习笔记)

&#x1f4d6; 前言&#xff1a;手机、PC机、电视等消费类产品非常普及&#xff0c;人们希望有一种短距离、低成本、小功耗的无线通信方式&#xff0c;实现不同功能单一设备的互联&#xff0c;提供小范围内设备的自组网机制&#xff0c;并通过一定的安全接口完成自组小网与广域…

Spring 依赖注入的三种方式优缺点

小王学习录 前言属性注入1. 属性注入的优点2. 属性注入的缺点 Setter注入Setter注入的优点Setter注入的缺点 构造方法注入1. 构造方法的优点 总结补充Aurowired注解和Resource注解的区别 前言 在前面的文章中介绍了基于注解的方式将Bean存储到Spring中, 接下来介绍如何基于注解…

Redis保证高可用的三种方式

Redis保证高可用主要有三种方式&#xff1a;主从、哨兵、集群。 主从复制了解吗&#xff1f; Redis主从复制简图 主从复制&#xff0c;是指将一台 Redis 服务器的数据&#xff0c;复制到其他的 Redis 服务器。前者称为 主节点(master)&#xff0c;后者称为 从节点(slave)。且…

【AIGC】prompt工程从入门到精通

注&#xff1a;本文示例默认“文心大模型3.5”演示&#xff0c;表示为>或w>&#xff08;wenxin)&#xff0c;有时为了对比也用百川2.0展示b>&#xff08;baichuan) 有时候为了模拟错误输出&#xff0c;会用到m>&#xff08;mock)表示&#xff08;因为用的大模型都会…

LLM微调(三)| 大模型中RLHF + Reward Model + PPO技术解析

本文将深入探讨RLHF&#xff08;Reinforcement Learning with Human Feedback&#xff09;、RM&#xff08;reward model&#xff09;和PPO&#xff08;Proximal Policy Optimizer&#xff09;算法的概念。然后&#xff0c;通过代码演示使用RLHF训练自己的大模型和奖励模型RM。…

鸿蒙OS应用开发之最简单的程序

鸿蒙OS应用开发之最简单的程序 前面介绍怎么样安装鸿蒙应用开发的环境&#xff0c;然后试着运行起来&#xff0c;并安装运行的虚拟机&#xff0c;以及对应9.0版本的API和SDK等软件。这样就具备了基本的开发基础&#xff0c;就可以进入创建应用程序开发了。 在我们起飞之前&…

idea使用maven的package打包时提示“找不到符号”或“找不到包”

介绍&#xff1a;由于我们的项目是多模块开发项目&#xff0c;在打包时有些模块内容更新导致其他模块在引用该模块时不能正确引入。 情况一&#xff1a;找不到符号 情况一&#xff1a;找不到包 错误代码部分展示&#xff1a; Failure to find com.xxx.xxxx:xxx:pom:0.5 in …

报错处理集

这个报错处理集的错误来源于编译arm平台的so文件产生的。但是后续可以补充成linux一个大的错误处理集。 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 第一次整理的时间是2023年12月8日10:05:59&#xff0c;以下错误来源于欧拉系统编译…

数字人知识库:Awesome-Talking-Head-Synthesis

数字人知识库&#xff1a;Awesome-Talking-Head-Synthesis 文章目录 数字人知识库&#xff1a;Awesome-Talking-Head-SynthesisDatasetsSurveyAudio-drivenText-drivenNeRF & 3DMetricsTools & SoftwareSlides & Presentations Gihub&#xff1a;https://github.co…

查看电脑cuda版本

1.找到NVODIA控制面板 输入NVIDIA搜索即可 出现NVIDIA控制面板 点击系统信息 2.WINR 输入nvidia-smi 检查了一下&#xff0c;电脑没用过GPU&#xff0c;连驱动都没有 所以&#xff0c;装驱动…… 选版本&#xff0c;下载 下载后双击打开安装 重新输入nvidia-smi 显示如下…

Python函数默认参数设置

在某些情况下&#xff0c;程序需要在定义函数时为一个或多个形参指定默认值&#xff0c;这样在调用函数时就可以省略为该形参传入参数值&#xff0c;而是直接使用该形参的默认值。 为形参指定默认值的语法格式如下&#xff1a; 形参名 默认值 从上面的语法格式可以看出&…

Java实现布隆过滤器

一、概述 布隆过滤器本质上是一个很长的二进制数组&#xff0c;主要用来判断一个数据存不存在数组里&#xff0c;如果存在就用1表示&#xff0c;不存在用0表示&#xff0c;它的优点是空间效率和查询时间都比一般的算法要好的多&#xff0c;缺点是有一定的误识别率和删除困难。 …

【Python系列】Python函数

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…