Java反射(三)
目录
1.反射与代理设计模式
2.反射与Annotation
3.自定义Annotation
4.Annotation整合工厂设计模式和代理设计模式
1.反射与代理设计模式
代理模式是指通过业务真实类实现业务接口,再通过设置代理类创建业务真实类子类从而间接访问业务真实类。但是这存在一个弊端,如果有1000个业务接口,对应的业务就需要实例化1000个对象,如下
代理设计模式
package Example1709;
//业务接口实现发送消息
interface Message{public void  send();
}
//业务接口真实实现
class MessageReal implements Message{@Overridepublic void send() {System.out.println("传输信息Message");}
}
//代理类
class Proxy{
//    通过实例化子类进行间接实现功能private MessageReal real = new MessageReal();public void getMessage() {real.send();}
}
public class javaDemo {public static void main(String[] args) {Proxy p = new Proxy();p.getMessage();}
}

可以看到代理类里面创建了Message实例对象,通过代理设计就可以实现客户端无需创建相应对象就能调用其中方法,只需要创建代理类即可。但是如果业务非常多,而我仅需要其中一个业务功能,那么代理类创建的对象将浪费。所以可以通过反射实现动态代理
java中特地有InvocationHandle接口实现动态代理,只需要让代理类实现该接口并且覆写其中方法invoke()方法调用 就能实现动态代理
案例代码:
package Example1710;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//业务接口
@FunctionalInterface
interface Message{public void send();
}
interface Connect{public boolean connect();
}
interface Close{public void close();
}
//业务实现类
class MessageReal implements Message{@Overridepublic void send() {System.out.println("输出信息");}
}
class ConnectReal implements Connect{@Overridepublic boolean connect() {System.out.println("连接成功");return true;}
}
class closeReal implements Close{@Overridepublic void close() {System.out.println("断开连接");}
}
//代理类需要实现InvocationHandle接口
class MessageProxy implements InvocationHandler {private Object object;public Object bind(Object object){this.object = object;return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);}
//覆写InvocationHandle接口中的invoke方法实现方法的调用@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("当调用方法时候自动执行这个函数");Object returnData = null;returnData = method.invoke(this.object,args);return returnData;}
}
public class javaDemo {public static void main(String[] args) {
//        向上转型实现需要的代理类Connect con = (Connect) new MessageProxy().bind(new ConnectReal());con.connect();}
}
 
2.反射与Annotation
在java.lang.reflect中通过AccesibleObject类可以获取Annotation(注解)。
AccessibleObject类获取Annotation的方法:
| 方法名 | 返回类型 | 描述 | 
|---|---|---|
| getAnnotations() | Annotation[] | 返回直接存在于此元素上的所有注解。 | 
| getAnnotation(Class<T> annotationClass) | <T extends Annotation> T | 如果此元素上存在指定类型的注解,则返回该注解;否则返回 null。 | 
| getDeclaredAnnotations() | Annotation[] | 返回直接存在于此元素上的所有已声明注解。 | 
| getDeclaredAnnotation(Class<T> annotationClass) | <T extends Annotation> T | 如果此元素上存在指定类型的注解,则返回该注解;否则返回 null。 | 
| isAnnotationPresent(Class<? extends Annotation> annotationClass) | boolean | 如果此元素上存在指定类型的注解,则返回 true;否则返回false。 | 
案例代码:
package Example1711;import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;@Deprecated
@FunctionalInterface
interface Face{void face();
}@SuppressWarnings("serial")
class Test implements Face, Serializable {@Overridepublic void face() {System.out.println("No face");}
}public class javaDemo {public static void main(String[] args) {Annotation tation[] = Face.class.getAnnotations();for (Annotation temp:tation) {System.out.println(temp);}Annotation taion2[] = Test.class.getAnnotations();for (Annotation temp:taion2) {System.out.println(temp);}}
}
 
上图中可以发现输出的只有interface接口的注解Annotation 但是类的上面的还有类内部的@Override却没有输出。原因在于Annotation的定义范围有关
下面任意拆出一个注解比如@FunctionInterface,分析源码
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface FunctionalInterface{}可以看到其中还定义的范围是Rentention,这里是RUNTIME意思是运行,
@Retention注解用于指定注解的保留策略,有三个可选值:
RetentionPolicy.SOURCE:注解只保留在源代码中,编译时会被忽略。
RetentionPolicy.CLASS:注解保留在编译后的字节码文件中,但在运行时无法获取到。
RetentionPolicy.RUNTIME:注解保留在编译后的字节码文件中,并且可以在运行时通过反射获取到。
问1:Connect con = (Connect) new MessageProxy().bind(new ConnectReal());其中new MessageProxy是创建代理对象,那return Proxy.newProxyInstance(object.getClass().getClassLoader(),this)也是创建代理对象,这不是重复了操作吗,如果和new MessageProxy作用不一样的话,那么newProxyInstance方法有什么作用
3.自定义Annotation
开发者可以根据自己的需要自定义Annotation,其中定义Annotaion时候需要使用@interface进行标记,同时通过@Target定义范围
Annotation操作范围:
| 元素类型 | @Target取值 | 描述 | 
|---|---|---|
| 类或接口 | ElementType.TYPE | 应用于类、接口或枚举类型。 | 
| 字段 | ElementType.FIELD | 应用于字段(成员变量)。 | 
| 方法 | ElementType.METHOD | 应用于方法。 | 
| 构造方法 | ElementType.CONSTRUCTOR | 应用于构造方法。 | 
| 方法参数 | ElementType.PARAMETER | 应用于方法的参数。 | 
| 局部变量 | ElementType.LOCAL_VARIABLE | 应用于局部变量。 | 
| 注解 | ElementType.ANNOTATION_TYPE | 应用于注解类型。 | 
| 包 | ElementType.PACKAGE | 应用于包声明。 | 
| 泛型类型参数 | ElementType.TYPE_PARAMETER | 应用于泛型类型参数。 | 
| 泛型类型参数的边界 | ElementType.TYPE_USE | 应用于泛型类型参数的使用处,例如类型转换、instanceof 表达式等 | 
| 类型导入声明(Java 9+) | ElementType.TYPE_IMPORT_DECLARATION | 应用于类型导入声明。 | 
| 模块导入声明(Java 9+) | ElementType.MODULE_IMPORT_DECLARATION | 应用于模块导入声明。 | 
| 类型使用 | ElementType.TYPE_USE或ElementType.TYPE_PARAMETER | 应用于类型使用或泛型类型参数。 | 
自定义案例代码:
如果@DefaultInterface对象有必要的数据传入,可以在@interface下设置value值。
package Example1713;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface useMessage{public String title();public String value();public String Default()default "默认值,如果调用则返回这个默认";
}class Message {@useMessage(title="Annotation的使用标题",value = "value的值")public void send(String str){System.out.println("输出信息"+str);}
}
public class javaDemo {public static void main(String[] args) throws Exception{String str;
//        调用方法Method mehod = Message.class.getMethod("send", String.class);
//        获取指定的AnnotationuseMessage msg = mehod.getAnnotation(useMessage.class);str = msg.Default();
//        实现方法调用mehod.invoke(Message.class.getDeclaredConstructor().newInstance(),str);str = msg.title();mehod.invoke(Message.class.getDeclaredConstructor().newInstance(),str);str = msg.value();mehod.invoke(Message.class.getDeclaredConstructor().newInstance(),str);}
}
4.Annotation整合工厂设计模式和代理设计模式
使用Annotation进行开发时候最大的特点就是可以将相应的配置信息写入Annotation后,在项目启动的时候就能够通过反射获取到相应的Annotation定义并操作
以下案例实现了通过Annotation整合工厂设计模式和代理设计模式
案例代码:
package Example1714;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;//业务接口
interface Message{public void send(String msg);
}
//业务实现类
class NetMessageImp implements Message{@Overridepublic void send(String msg) {System.out.println("通过网络进行发送消息"+msg);}
}
class CloudMessageImp implements Message{@Overridepublic void send(String msg) {System.out.println("通过云网络进行发送消息"+msg);}
}
//定义工厂类
class Factory{
//    私有化工厂类无法在外部实例化private Factory(){};
//    通过getInstance获取实例化的对象public static<T> T getInstance(Class<T> clazz){try {return (T) new MessageProxy().bind(clazz.getDeclaredConstructor().newInstance());} catch (Exception e){e.printStackTrace();return null;}}
}
//设置自定义Annotation
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface RealInstance {public Class<?> claszz();}@RealInstance(claszz = NetMessageImp.class)
class MessageService{private Message msg;public MessageService(){
//        getAnnotation需要对应的classRealInstance cls = MessageService.class.getAnnotation(RealInstance.class);this.msg = (Message) Factory.getInstance(cls.claszz());}public void send(String msg){this.msg.send(msg);}
}
//设置代理类
class MessageProxy implements InvocationHandler{private Object target;
//    绑定并创建指定对象public  Object bind(Object target){this.target = target;return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);}
//    设置连接函数public boolean connect(){System.out.println("连接成功");return true;}
//    设置关闭函数public void close(){System.out.println("断开连接");}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if (this.connect()){return method.invoke(this.target,args);}}catch (Exception e){e.printStackTrace();}finally {this.close();}return null;}
}
public class javaDemo {public static void main(String[] args) {MessageService instance = new MessageService();instance.send("我去,这东西是真的复杂啊,需要好好仔细读完啊");}
}

Message接口是一个业务接口,定义了发送消息的方法。
NetMessageImp和CloudMessageImp是两个实现了Message接口的具体业务类,分别通过网络和云网络发送消息。
Factory是一个工厂类,通过使用代理模式创建并返回代理对象的实例。
RealInstance是一个自定义注解,用于标记需要被代理的具体业务类。
MessageService是一个具有注解的类,其中msg字段是通过工厂类创建的代理对象,用于发送消息。
MessageProxy是一个实现了InvocationHandler接口的代理类,负责在发送消息前后进行额外的处理,比如连接和关闭连接。- 在主函数中,创建
MessageService实例并调用send方法发送消息。
问1:public static<T> T getInstance(Class<T> clazz)为什么要用<T>,作为泛型方法是如何使用的?
public static <T> T getInstance(Class<T> clazz)中的<T>是泛型声明,它允许我们在方法中使用泛型类型。其中,T是一个类型参数,表示方法的返回类型和传入参数的类型。通过在方法声明中使用泛型,我们可以在调用时指定具体的类型,并在编译时进行类型检查。
问2:在这段整合工厂设计和代理设计时候,工厂类和代理类分别担任了什么样的角色?他们完成了什么职责,为什么要加入MessageService?
- 工厂类(
Factory)的角色是创建并返回代理对象的实例。它的职责是根据传入的业务接口类型,使用代理模式创建该接口的代理对象。工厂类的目的是为了提供一种通用的方式来创建代理对象。- 代理类(
MessageProxy)的角色是实现了InvocationHandler接口的代理类。它的职责是在代理对象的方法调用前后进行额外的处理。在这个例子中,它负责在发送消息前后进行连接和关闭连接的操作。
MessageService是一个业务类,其中的msg字段通过工厂类创建的代理对象,用于发送消息。MessageService通过使用代理对象,可以在发送消息的过程中加入额外的处理逻辑,而无需直接引用具体的业务实现类。
问3:Proxy.newProxyInstance()方法如何使用,该怎么传入参数?
Proxy.newProxyInstance()方法用于创建代理对象。它接受三个参数:
ClassLoader loader:类加载器,用于在运行时加载代理类。一般可以使用业务接口的类加载器。
Class<?>[] interfaces:代理类要实现的接口数组。代理对象将实现这些接口,并将方法调用委托给InvocationHandler的invoke()方法。
InvocationHandler h:代理对象在方法调用时的处理器,需要实现InvocationHandler接口
问4:方法调用method.invoke()如何传入参数?
问4:
method.invoke()方法用于调用代理对象的方法。它接受两个参数:
Object obj:方法所属的对象,即代理对象。
Object... args:方法的参数数组。
问5:在设计模式中,工厂设计模式,代理设计模式,业务处理类的作用?
- 在设计模式中,工厂模式的作用是将对象的创建过程封装起来,并且提供一个统一的接口来获取对象的实例。通过使用工厂类,可以实现对象的创建和管理的解耦,使得代码更加灵活和可维护。
- 代理模式的作用: 代理模式充当了客户端和实际业务对象之间的中介角色,为客户端提供一种间接访问对象的方式。具体来说,代理类封装了实际业务对象并提供了一个类似的接口,使得客户端可以通过代理类来访问实际业务对象。代理类还可以在访问被代理对象之前或之后执行额外的逻辑(例如验证、缓存、日志记录等)。代理模式的优点是它可以在不修改客户端的情况下对实际业务对象进行控制和扩展。
- 业务处理类的作用: 业务处理类是实际执行业务逻辑的类。它是根据特定需求实现业务功能的地方。在代理模式中,业务处理类是被代理的真实对象。它定义了代理类需要代理的具体业务逻辑,代理类会将请求传递给业务处理类并最终由业务处理类完成实际的业务操作。
相关文章:
 
Java反射(三)
目录 1.反射与代理设计模式 2.反射与Annotation 3.自定义Annotation 4.Annotation整合工厂设计模式和代理设计模式 1.反射与代理设计模式 代理模式是指通过业务真实类实现业务接口,再通过设置代理类创建业务真实类子类从而间接访问业务真实类。但是这存在一个弊…...
ansible-playbook roles编写lnmp剧本
目录 集中式编写lnmp剧本 执行 分布式编写lnmp剧本 一定要设置ssh免交互 nginx mysql php 执行 集中式编写lnmp剧本 vim /etc/ansible/lnmp.yml - name: lnmp playhosts: dbserversremote_user: roottasks:- name: perpare condifurecopy: src/etc/yum.repos.d/nginx.r…...
相机可用性变化监听AvailabilityCallback流程分析
相机可用性变化监听及流程分析 一、接口说明  相机可用性变化监听可以通过CameraManager中的接口registerAvailabilityCallback()来设置回调,接口如下: /** *注册一个回调以获得有关相机设备可用性的通知。 * *<p>再次注册相同的回调将用提供…...
使用Python多线程实现生产者消费者模型
“Talk is cheap, show me the code.” 废话不多说,直接上代码: """ 生产者消费者模型 Python实现 """ import queue import threading import random import timeclass ConsProd:# 队列参数_que None # 队列# 生产者…...
 
Notepad++工具通过正则表达式批量替换内容
1.每行末尾新增特定字符串 CtrlH弹出小窗口;查找目标输入$,替换为输入特定字符串;选中循环查找,查找模式选正则表达式;最后点击全部替换 2.每行行首新增特定字符串 CtrlH弹出小窗口;查找目标输入^&…...
从零构建深度学习推理框架-3 手写算子relu
Relu介绍: relu是一个非线性激活函数,可以避免梯度消失,过拟合等情况。我们一般将thresh设为0。 operator类: #ifndef KUIPER_COURSE_INCLUDE_OPS_OP_HPP_ #define KUIPER_COURSE_INCLUDE_OPS_OP_HPP_ namespace kuiper_infer {…...
 
想做上位机,学C#还是QT?
学习C#还是Qt,取决于你的具体需求和偏好。 如果你计划开发跨平台的桌面应用程序,并且希望使用一种更轻量级、直观的界面框架,那么Qt可能是一个不错的选择。Qt是一个功能丰富且成熟的跨平台框架,支持多种开发语言(包括…...
 
Ansible —— playbook 剧本
Ansible —— playbook 剧本 一、playbook的概述1.playbook简介2.什么是Ansible playbook剧本?3.Ansible playbook剧本的特点4.如何使用Ansible playbook剧本?5.playbooks 本身由以下各部分组成 二、playbook示例1.运行playbook2.定义、引用变量3.指定远…...
ARM寻址方式
寻址方式 寻址方式是根据指令中给出的地址码字段来实现寻找操作数地址的方式,ARM中有以下8种基本的寻址方式。 1、寄存器寻址 将寄存器中的值作为操作数,指令中的地址码字段是寄存器编号。 MOV R1,R2 ;R1 R2 ADD R0,R1,R2 ;R0 R1 R22、立即寻…...
 
【JAVA】String ,StringBuffer 和 StringBuilder 三者有何联系?
个人主页:【😊个人主页】 系列专栏:【❤️初识JAVA】 文章目录 前言StringBufferStringBuffer方法 StringBuilderStringBuilder方法 String ,StringBuffer 和 StringBuilder的区别String和StringBuffer互相转换 前言 在之前的文章…...
关于计数以及Index返回订单号升级版(控制字符长度,控制年月标记)
数据库表操作: EXEC sys.sp_dropextendedproperty nameNName , level0typeNSCHEMA,level0nameNdbo, level1typeNTABLE,level1nameNSetNoIndexGOEXEC sys.sp_dropextendedproperty nameNMS_Description , level0typeNSCHEMA,level0nameNdbo, level1typeNTABLE,level…...
 
【计算机网络】11、网桥(bridge)、集线器(hub)、交换机(switch)、路由器(router)、网关(gateway)
文章目录 一、网桥(bridge)二、集线器(hub)三、交换机(switch)四、路由器(router)五、网关(gateway) 对于hub,一个包过来后,直接将包转发到其他口。 对于桥&…...
第九篇-自我任务数据准备
格式化自我意识数据用于ChatGLM微调 准备数据源 https://github.com/hiyouga/ChatGLM-Efficient-Tuning cd data self_cognition.json代码self_process.py #!/usr/bin/python # -*- coding: UTF-8 -*- # 读取self_cognition自我认知解析并写入转换新文件import json# 读取se…...
 
2023.8.1号论文阅读
文章目录 MCPA: Multi-scale Cross Perceptron Attention Network for 2D Medical Image Segmentation摘要本文方法实验结果 SwinMM: Masked Multi-view with SwinTransformers for 3D Medical Image Segmentation摘要本文方法实验结果 MCPA: Multi-scale Cross Perceptron Att…...
webpack优化前端框架性能
webpack优化目的 webpack优化目的1. 提升开发体验提升开发体验使用 SourceMap 2. 提升打包构建速度提升打包构建速度(开发模式)提升打包速度 oneOf提升打包速度 include(包含)/exclude(排除)提升第二次打包…...
Unity UGUI的Outline(描边)组件的介绍及使用
Unity UGUI的Outline(描边)组件的介绍及使用 1. 什么是Outline(描边)组件? Outline(描边)组件是Unity UGUI中的一种特效组件,用于给UI元素添加描边效果。通过设置描边的颜色、宽度和模糊程度,可以使UI元素在视觉上更加突出。 2. Outline(描…...
爆改vue3 setup naiveui可编辑table
使用naiveui官网的可编辑table总是报错,所以手写了一个 思路:table数据数组unitMsgArr对应一个布尔的数组isEditArr ,点击table可编辑的行数据的时候,更改对应的isEdit为true,此时渲染组件EditCom,在EditC…...
 
功率放大器的种类有哪三种类型
功率放大器是一种能将输入信号转换为更高功率输出的电子设备。在电子工程和音频领域中,功率放大器通常被分为三种类型:A类、B类和AB类。下面安泰电子将详细介绍这三种类型的功率放大器及其特点。 A类功率放大器 A类功率放大器是一种基本的线性功率放大器…...
HDFS 分布式存储 spark storm HBase
HDFS 分布式存储 spark storm HBase 分布式结构 master slave name node client 负责文件的拆分 128MB 3份 data node MapReduce 分布式计算 离线计算 2.X之前 速度比较慢 对比spark 编程思想 Map 分 Reduce 合 hadoop streaming Mrjob Yarn 资源管理 cpu 内存 MapReduc…...
Vue3文字实现左右和上下滚动
可自定义设置以下属性: 滚动文字数组(sliderText),类型:Array<{title: string, link?: string}>,必传,默认[] 滚动区域宽度(width),类型:…...
 
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
 
浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...
 
Linux 下 DMA 内存映射浅析
序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存,但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程,可以参考这篇文章,我觉得写的非常…...
Python学习(8) ----- Python的类与对象
Python 中的类(Class)与对象(Object)是面向对象编程(OOP)的核心。我们可以通过“类是模板,对象是实例”来理解它们的关系。 🧱 一句话理解: 类就像“图纸”,对…...
java+webstock
maven依赖 <dependency><groupId>org.java-websocket</groupId><artifactId>Java-WebSocket</artifactId><version>1.3.5</version></dependency><dependency><groupId>org.apache.tomcat.websocket</groupId&…...
