Java反射机制和动态代理

反射和动态代理

  • 反射
    • 前言
    • 获取class对象的方式
    • 反射获取构造方法
    • 反射获取成员变量
    • 反射获取成员方法
    • 实例
  • 动态代理

反射

前言

什么是反射?
反射允许对成员变量,成员方法和构造方法的信息进行编程访问。
为什么用反射 / 反射的作用?
可以轻易地获取成员变量、构造方法和成员方法的所有信息。
①获取一个类里面所有的信息,获取到了之后,再执行其他的业务逻辑。
②结合配置文件,动态的创建对象并调用方法。

获取class对象的方式

三种方式
Class.forName("全类名");
类名.class
对象.getClass()
使用时机
这三种方式的使用时机实际上和Java文件的编译过程息息相关:
在这里插入图片描述

源代码阶段没有把代码加载到内存当中,只是在硬盘中进行的操作,这一阶段使用第一种方式获得class字节码文件的对象;运行Java代码时,需要将类的字节码文件加载到内存中,这个阶段是加载阶段,该阶段使用第二种方式;在内存中创建某个类的对象时为运行阶段,该阶段使用第三种方式。

具体实现

//1. Class.forName("全类名") 全类名就是:包名+类名
//clazz_one就是Student类的字节码文件
//第一种方式最为常用
Class clazz_one = Class.forName("com.wmy.myreflect1.Student");
System.out.println(clazz_one);//2. 类名.class
//第二种方式更多的是当做参数来传递
Class clazz_two = Student.class;
System.out.println(clazz_two);//3. 对象.getClass()
//当我们已经有了这个类的对象时 才可以使用方式三
Class clazz_three = new Student().getClass();
System.out.println(clazz_three);
System.out.println(clazz_one == clazz_two);
System.out.println(clazz_two == clazz_three);
System.out.println(clazz_one == clazz_three);

运行结果
在这里插入图片描述

反射获取构造方法

在Java中,存在“万物皆对象”的思想,比如说class字节码文件是Class类的对象,那么构造方法可以看作是Constructor类的对象、成员变量(字段)可以看作是Field类的对象、成员方法可以看作是Method类的对象。

//1. 获取class字节码文件对象
Class clazz = Class.forName("com.wmy.myreflect1.demo02.Student02");
//2. 获取构造方法
System.out.println("获取公共构造方法:");
Constructor[] cons1 = clazz.getConstructors();
for (Constructor con : cons1){System.out.println(con);
}
System.out.println("分割线-----------------------------------"+"\n");
System.out.println("获取所有构造方法(含私有):");
Constructor[] cons2 = clazz.getDeclaredConstructors();
for (Constructor con : cons2){System.out.println(con);
}
System.out.println("注:虽然该方法可以获得私有构造方法,但是无法通过这种方式完成私有构造方法new一个对象出来");
System.out.println("分割线-----------------------------------"+"\n");
System.out.println("根据构造方法中参数类型和参数数量的不同 向getDeclaredConstructor中传入参数类型的字节码文件即可获得对应的构造方法:");
Constructor con1 = clazz.getDeclaredConstructor();
Constructor con2 = clazz.getDeclaredConstructor(String.class);
Constructor con3 = clazz.getDeclaredConstructor(int.class);
Constructor con4 = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(con1);
System.out.println(con2);
System.out.println(con3);
System.out.println(con4);
System.out.println("分割线-----------------------------------"+"\n");
System.out.println("获取权限修饰符");
int modifiers = con4.getModifiers();
System.out.println("1表示公有public 2表示私有private");
System.out.println(modifiers);
System.out.println("分割线-----------------------------------"+"\n");
System.out.println("暴力反射:表示临时取消权限校验");
con4.setAccessible(true);
Student02 stu = (Student02)con4.newInstance("张三", 23);
System.out.println(stu);

在这里插入图片描述

反射获取成员变量

//1. 获取class字节码文件的对象
Class clazz = Class.forName("com.wmy.myreflect1.demo03.Student03");
//2. 获取成员变量
System.out.println("获取所有公共成员变量:");
Field[] fields1 = clazz.getFields();
for (Field field : fields1){System.out.println(field);
}
System.out.println("分割线-----------------"+"\n");
System.out.println("获取所有成员变量(含私有):");
Field[] fields2 = clazz.getDeclaredFields();
for (Field field : fields2){System.out.println(field);
}
System.out.println("分割线-----------------"+"\n");
System.out.println("获取单个成员变量:");
Field gender = clazz.getField("gender");
System.out.println(gender);
Field name = clazz.getDeclaredField("name");
System.out.println(name);
Field age = clazz.getDeclaredField("age");
System.out.println(age);
System.out.println("分割线-----------------"+"\n");
System.out.println("获取权限修饰符:");
int modifiers = name.getModifiers();
System.out.println(modifiers);
System.out.println("获取成员变量名称:");
String n = name.getName();
System.out.println(n);
System.out.println("获取成员变量类型:");
Class t = name.getType();
System.out.println(t);
System.out.println("获取成员变量记录的值:");
Student03 s = new Student03("张三",23,"男");
name.setAccessible(true);
String value = (String) name.get(s);
System.out.println(value);
System.out.println("修改对象里面记录的值:");
name.set(s,"李四");
System.out.println(s);

在这里插入图片描述

反射获取成员方法

//1. 获取class字节码文件对象
Class clazz = Class.forName("com.wmy.myreflect1.demo04.Student04");
//2. 获取成员方法
System.out.println("获取所有方法对象(包含父类中所有的公共方法):");
Method[] methods1 = clazz.getMethods();
for (Method method : methods1){System.out.println(method);
}
System.out.println("分割线-----------------"+"\n");
System.out.println("获取所有方法对象(不能获取父类的,但是可以获取本类中私有的方法):");
Method[] methods2 = clazz.getDeclaredMethods();
for (Method method : methods2){System.out.println(method);
}
System.out.println("分割线-----------------"+"\n");
System.out.println("获取指定的单一方法:");
Method m = clazz.getDeclaredMethod("eat", String.class, int.class);
System.out.println(m);
System.out.println("获取方法的修饰符:");
int modifiers = m.getModifiers();
System.out.println(modifiers);
System.out.println("获取方法的名字:");
String name = m.getName();
System.out.println(name);
System.out.println("获取方法的形参:");
Parameter[] parameters = m.getParameters();
for (Parameter parameter : parameters) {System.out.println(parameter);
}
System.out.println("获取方法抛出的异常:");
Class[] exceptionTypes = m.getExceptionTypes();
for (Class exceptionType : exceptionTypes) {System.out.println(exceptionType);
}
System.out.println("获取方法的返回值:");
Student04 s = new Student04();
m.setAccessible(true);
String result = (String)m.invoke(s,"石乐志",996);
System.out.println(result);

实例

需求1
保存信息:对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去。
实现

public class MyReflectDemo {public static void main(String[] args) throws IllegalAccessException, IOException {/** 对于任意一个对象 都可以把对象所有的字段名和值 保存到文件中去* */Student s = new Student("小A" , 23, '女' , 167.5 , "睡觉");Teacher t = new Teacher("gls" , 1000);saveObject(t);}//把对象的所有成员变量名和值保存到本地文件中private static void saveObject(Object obj) throws IllegalAccessException, IOException {//1. 获取字节码文件的对象Class clazz = obj.getClass();//创建IO流BufferedWriter bw = new BufferedWriter(new FileWriter("G:\\JavaWorks_IntelliJIDEA\\myreflect\\src\\main\\java\\com\\wmy\\myreflect1\\record.txt"));//2. 获取所有的成员变量Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {field.setAccessible(true);//获取成员变量的名字String name = field.getName();//获取成员变量的值Object value = field.get(obj);//写出数据bw.write(name+"="+value);bw.newLine();}bw.close();}
}

结果
在这里插入图片描述
需求2
跟配置文件结合动态创建:反射可以和配置文件结合的方式,动态的创建对象,并调用方法。
实现
prop.properties

classname=com.wmy.myreflect1.case2.Student
method=study

com/wmy/myreflect1/case2/MyReflectDemo.java

public class MyReflectDemo {public static void main(String[] args) throws IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {/** 反射可以和配置文件结合的方式 动态地创建对象 并调用方法* *///1.读取配置文件中的信息Properties prop = new Properties();FileInputStream fis = new FileInputStream("G:\\JavaWorks_IntelliJIDEA\\myreflect\\prop.properties");prop.load(fis);fis.close();System.out.println(prop);//2.获取全类名和方法名String className = (String)prop.get("classname");String methodName = (String)prop.get("method");System.out.println(className);System.out.println(methodName);//3.利用反射去创建对象并运行方法Class clazz = Class.forName(className);//获取构造方法Constructor con = clazz.getDeclaredConstructor();Object o = con.newInstance();System.out.println(o);//获取成员方法并运行Method method = clazz.getDeclaredMethod(methodName);method.setAccessible(true);method.invoke(o);}
}

动态代理

1.什么是动态代理?
动态代理可以无侵入式的给代码增加额外的功能。
在这里插入图片描述
2.程序为什么需要代理?
对象如果嫌身上干的事太多的话,可以通过代理来转移部分职责。
对象有什么方法想被代理,代理就一定要有对应的方法。
3.代理长什么样?
代理里面就是对象要被代理的方法。
4.Java通过什么来保证代理的样子?
通过接口保证,后面的对象和代理需要实现同一个接口,接口中就是被代理的所有方法。
5.如何为Java对象创建一个代理对象?
java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interface,InvocationHandler h)
参数一:用于指定用哪个类加载器 去加载生成的代理类
参数二:指定接口 这些接口用于指定生成的代理长什么样 也就是有哪些方法
参数三:用来指定生成的代理对象要干什么事情

需求
实现BigStar类中成员方法的动态代理。
步骤
1.创建BigStar类(记得实现步骤2中的接口)
com/wmy/mydynamicproxy/BigStar.java

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+"正在让你蠢蠢欲动");}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "BigStar{" +"name='" + name + '\'' +'}';}
}

2.封装要代理的方法为接口
com/wmy/mydynamicproxy/Star.java

public interface Star {//我们可以把所有想要被代理的方法定义在接口当中//唱歌public abstract String sing(String name);//跳舞public abstract void dance();
}

3.创建ProxyUtil类用于创建代理
com/wmy/mydynamicproxy/ProxyUtil.java

/*
* 类的作用:
*       创建一个代理
* */
public class ProxyUtil {/** 方法的作用:*       给一个明星的对象创建一个代理* 形参:*       被代理的明星对象* 返回值:*       给明星创建的代理* 需求:*       外面的人想要大明星唱一首歌*       1.获取代理的对象*           代理对象 = ProxyUtil.createProxy(大明星的对象);*       2.再调用代理的唱歌的方法*           代理对象.唱歌的方法();* */public static Star createProxy(BigStar bigStar){/** public static Object newProxyInstance(ClassLoader loader, Class<?>[] interface,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 {/** 参数一:代理的对象* 参数二:要运行的方法 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;}
}

4.创建测试类测试动态代理的过程
com/wmy/mydynamicproxy/Test.java

    /** 需求:*       外面的人想要大明星唱一首歌*       1.获取代理的对象*           代理对象 = ProxyUtil.createProxy(大明星的对象);*       2.再调用代理的唱歌的方法*           代理对象.唱歌的方法();* */
public class Test {public static void main(String[] args) {//1.获取代理的对象BigStar bigStar = new BigStar("鸡哥");Star proxy = ProxyUtil.createProxy(bigStar);//2.调用唱歌的方法String result = proxy.sing("姬霓太美");System.out.println(result);//2.调用跳舞的方法proxy.dance();}
}

5.效果
在这里插入图片描述

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

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

相关文章

图像分割-漫水填充法 floodFill (C#)

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 本文的VB版本请访问&#xff1a;图像分割-漫水填充法 floodFill-CSDN博客 FloodFill方法是一种图像处理算法&#xff0c;它的目的是…

【SpringBoot框架篇】34.使用Spring Retry完成任务的重试

文章目录 简要1.为什么需要重试&#xff1f;2.添加maven依赖3.使用Retryable注解实现重试4.基于RetryTemplate模板实现重试 简要 Spring实现了一套重试机制&#xff0c;功能简单实用。Spring Retry是从Spring Batch独立出来的一个功能&#xff0c;已经广泛应用于Spring Batch,…

哪些洗地机比较好?洗地机选购指南

随着社会生活水平的提高&#xff0c;人们对居家环境的卫生和清洁要求不断提升。家用洗地机作为一种先进的清洁工具&#xff0c;带来了许多便利和优势&#xff0c;特别是在解决一些特殊需求的家庭环境方面。 以下是一些家用洗地机的优势和适用场景&#xff1a; 1.高效清洁&…

Hive用户自定义函数之UDF开发

在进行大数据分析或者开发的时候&#xff0c;难免用到Hive进行数据查询分析&#xff0c;Hive内置很多函数&#xff0c;但是会有一部分需求需要自己开发&#xff0c;这个时候就需要自定义函数了&#xff0c;Hive的自定义函数开发非常方便&#xff0c;今天首先讲一下UDF的入门开发…

爬虫如何获取免费代理IP(二)

89ip代理爬取代码实现 一、代码实现 import requests import time import random from fake_useragent import UserAgent from lxml import etree import os import csv""" 89ip代理爬取 """class IPSipder(object):def __init__(self):self.u…

macbook电脑2024免费好用的系统清理优化软件CleanMyMac X4.14.7

CleanMyMac X2024来帮助你找到和删除不需要的文件。CleanMyMac X是一款专业的mac清理软件&#xff0c;它可以智能地扫描你的磁盘空间&#xff0c;找出并删除大型和旧文件&#xff0c;系统垃圾&#xff0c;iTunes垃圾&#xff0c;邮件附件&#xff0c;照片库垃圾等&#xff0c;让…

那些高级工程师才知道的只有几行代码却功能强大python自动化脚本,号称掌握这个python库让你工作效率变得比别人遥遥领先

那些高级工程师才知道的只有几行代码却功能强大python自动化脚本,号称掌握这个python库让你工作效率变得比别人遥遥领先。 如果你也厌倦了每天重复同样乏味的工作?Python,凭借它的简单和通用性,能够为你的问题提供最佳方案。 在本文中,我们将探索10个Python脚本,这些脚本…

数据结构学习 Jz48最长不含重复字符的子字符串

关键词&#xff1a;哈希表 动态规划 滑动窗口 用时&#xff1a;40min 哈希表 动态规划 题解&#xff1a;我觉得这个写的很好。 题目&#xff1a; 方法一&#xff1a; 哈希表 滑动窗口 思路&#xff1a; 我一开始没想到用一个左指针做滑动窗口。 哈希表&#xff1a;存之前…

七:Day06_redis高级01

第一章 Redis入门 1.1 节 什么是NoSql型数据库 NoSQL ,泛指非关系型的数据库, NoSQL Not Only SQL,它可以作为关系型数据库的良好补充。NoSQL 不依赖业务逻辑方式存储&#xff0c;而以简单的key-value模式存储。因此大大的增加了数据库的扩展能力。 SQLNoSQL数据结构结构化非…

P59 生成式对抗网络GAN-理论介绍 Theory behind GAN

Object Normal Distribution 的数据 经过 Generator 后生成分布更加复杂的PG. 真实数据的分布为 Pdata , 希望 PG和Pdata 越近越好 LOSS 是 两者之间的分布距离 问题: 如何计算 divergence? Sampling is goog enough Discriminator 希望V越大越好 y~Pdata 代表从 Pdata里…

zabbix离线安装 zabbix api批量添加主机

持续更新最新版本… 全自动安装方法 下载一键安装脚本 一键安装脚本执行命令全自动安装 tar -zxvf zabbix-rocky_8_zabbix_6.0.x_mysql.tar.gz cd zabbix-rocky_8_zabbix_6.0.x_mysql sh autosetup.sh installRocky8.9系统下载Rocky系统bug报告 手动安装方法 操作系统&…

Java 语言概述

Java 概述 是 SUN&#xff08;Stanford University Network&#xff0c;斯坦福大学网络公司&#xff09;1995年推出的一门高级编程语言 是一种面向 Internet 的编程语言。Java 一开始富有吸引力是因为 Java 程序可以在 Web 浏览器中运行。这些 Java 程序被称为 Java 小程序&am…