反射、代理模式、注解

news2024/10/13 6:13:18

目录

一.Java反射

1.1反射的第一步:获取Class类的对象

1.2使用反射获取构造器对象并使用

1.3使用反射获取成员变量对象并使用

1.4使用反射获取成员方法对象并使用

二.代理模式

 2.1概述

2.2代理模式在Java中的应用

2.3静态代理

2.4动态代理

2.4.1JDK动态代理

①实现 InvocationHandler 接口,用来做方法拦截

②通过 Proxy.newProxyInstance 创建代理实例

2.4.2cglib动态代理

①实现 MethodInterceptor 接口,用来做方法拦截

②设置父类字节码、拦截处理,获取代理对象

三.注解

3.1元注解

3.2注解的本质

3.3注解的解析


一.Java反射

反射指的是允许以编程方式访问已加载类的成分(成员变量、方法、构造器等)。

1.1反射的第一步:获取Class类的对象

获取Class对象的三种方式:

  • 类名.class
  • Class.forName(全类名,即包名+类名)
  • Object提供的方法:对象.getClass()

1.2使用反射获取构造器对象并使用

获取到构造器对象的作用:依然是初始化对象

setAccessible(boolean)表明反射可以破坏封装性,私有的构造器也可以用来初始化对象

1.3使用反射获取成员变量对象并使用

获取到成员变量的作用:依然是为对象赋值、取值

setAccessible(boolean)表明反射可以破坏封装性,私有的属性也可以赋值、取值

1.4使用反射获取成员方法对象并使用

获取成员方法的作用:依然是执行方法

setAccessible(boolean)表明反射可以破坏封装性,私有的方法也可以调用执行

二.代理模式

 2.1概述

二十三种设计模式中的一种,属于结构型模式。它的作用就是通过提供一个代理类,让我们在调用目标 方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用。让不属于目标方法核心逻辑 的代码从目标方法中剥离出来——解耦

意义:目标对象只需要关心自己的实现细节,通过代理对象来实现功能的增强,可以扩展目标对象的功能。体现了非常重要的编程思想:不能随便修改源码,如果需要修改源码,通过修改代理的方式来实现功能的拓展。

2.2代理模式在Java中的应用

  • 统一异常处理
  • Mybatis使用了代理
  • Spring AOP实现原理
  • 日志框架

2.3静态代理

  • 需要手写代理类
  • 代理目标确定

案例:给添加学生的service里增强事务操作

IStudentService

StudentServiceImpl(需要被代理的对象)

ProxyStudent(代理对象)

静态代理的缺点

  • 不利于代码拓展,比如接口中新添加一个抽象方法时,所有实现类都需要重新实现,否则报错
  • 代理对象需要创建很多,这种设计很不方便和麻烦

2.4动态代理

2.4.1JDK动态代理

在不改变原有功能代码的前提下,能够动态的实现方法的增强

①实现 InvocationHandler 接口,用来做方法拦截

invoke方法:代理对象要执行的方法,实现目标方法的执行和功能增强

  • proxy:生成的代理对象
  • method:原始(目标)方法的对象
  • args:参数数组

②通过 Proxy.newProxyInstance 创建代理实例
  • ClassLoader loader:类加载器,直接通过需要代理的类获取就行
  • Class<?>[] interfaces:目标类所实现的所有接口
  • InvocationHandler:方法拦截处理器,可以在里面实现方法的增强

saveProxyClass用于 生成代理类的字节码文件

private void saveProxyClass(String path){
        byte[] $proxy1s = ProxyGenerator.generateProxyClass("$Proxy1",
                StudentServiceImpl.class.getInterfaces());
        FileOutputStream outputStream=null;
        try {
            outputStream=new FileOutputStream(path+"$Proxy1.class");
            outputStream.write($proxy1s);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(outputStream!=null){
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

我们可以看一下生成的代理类,可以发现代理类继承了 Proxy 并实现了目标类实现的所有接口,然后通过反射获取了目标方法的对象

2.4.2cglib动态代理

JDK动态代理有一个前提,需要代理的类必须实现接口,如果没有实现接口,只能通过CGLIB来实现,其实就是对于JDK动态代理的一个补充

①实现 MethodInterceptor 接口,用来做方法拦截

②设置父类字节码、拦截处理,获取代理对象

我们可以看一下生成的代理类

  • 通过继承的方式去获取到目标对象的方法
  • 通过传递方法拦截器 Methodlnterceptor 实现方法拦截,在这里面做具体的增强
  • 调用生成的代理类对象具体执行重写的 save 方法,直接去调用方法拦截器里面的 intercept 方法
  • 前后加上了增强操作,从而实现了不修改目标代码实现业务增强

三.注解

Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。 Java 语言中的类、构造器、方法、成员变量、参数等都可以被注解进行标注。

JDK中内置的一些注解:

  • @Override:检测被该注解标注的方法是否是继承自父类(接口)的
  • @Deprecated:该注解标注的内容,表示已过时
  • @Suppresswarnings: 压制警告,一般传递参数 "all"

自定义注解:

@Target(ElementType.TYPE)//类级别,元注解
@Retention(RetentionPolicy.RUNTIME)//自定义注解的存活范围,元注解
public @interface Check {
    public int value() default 1;
}

3.1元注解

元注解:用于描述注解的注解

  • @Target:描述注解能够作用的位置
  • @Retention:描述注解被保留的阶段
  • @Documented:描述注解是否被抽取到API文档中
  • @Inherited:描述注解是否被子类继承
  1. RetentionPolicy.SOURCE:这类注解在变成class文件之前就被注解处理器(Annotation Processor)去掉了,等于说不会被编译到class文件中
  2. RetentionPolicy.Class:会被编译到class文件中,不过在加载后该类型的注解就会被丢弃
  3. RetentionPolicy.RUNTIME:不光会被编译到class文件,在加载之后也会被保留,在运行期间可以反射读取对应的一些方法和变量信息

3.2注解的本质

我们先用 javac 对 Check.java 进行编译,然后再用 javap 对 Check.class 进行反编译,查看其源代码。

可以发现,注解的本质上就是一个接口,该接口默认继承 Annotation 接口。注解中的属性即为接口中的抽象方法。

特别注意注解中的属性返回类型是有限制的,只能是如下的类型:

  • 基本数据类型
  • String
  • 枚举
  • 注解
  • 以上类型的数组

3.3注解的解析

注解的解析就是判断是否存在注解,存在注解就解析出内容。注解在哪个成分上,我们就先拿哪个成分对象。

  • 比如注解作用成员方法,则要获得该成员方法对应的Method对象,再来拿上面的注解  
  • 比如注解作用在类上,则要该类的Class对象,再来拿上面的注解  
  • 比如注解作用在成员变量上,则要获得该成员变量对应的Field对象,再来拿上面的注解

与注解解析相关的接口

AnnotatedElement:该接口定义了与注解解析相关的解析方法

所有的类成分Class, Method , Field , Constructor,都实现了AnnotatedElement接口,他们都拥有解析注解的能力

案例:获取自定义注解的className和methodName,执行该方法

自定义注解 Pro

获取上边的注解对象,其实就是在内存中生成了一个实现该注解接口的实现对象

public class ProImpl implements Pro{
        @Override
        public String methodName() {
             ......
             return "com.annotation.parse.Print";//返回使用注解时传的参数
        }
        @Override
        public String className() {
             ......
             return "print";//返回使用注解时传的参数
        }
}

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

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

相关文章

第60节——使用redux-toolkit实战一个商品列表的增删查改

一、样例 二、需求 调用goods.js这个单例完成对goods数据的增删查改 class Goods {constructor() {const data localStorage.getItem("qf-goods-data");this.goods data ? JSON.parse(data) : [];}time 500;/*** 获取商品* returns*/getGoods() {return new Pr…

序列化和反序列化指令在PLC通信上的应用

在了解本篇博客之前,大家可以熟悉下序列化指令的相关介绍,详细内容如下: 博途PLC 1200/1500 PLC 序列化和反序列化指令编程应用_博图序列化和反序列化-CSDN博客序列化最重要的作用:在传递和保存对象时.保证对象的完整性和可传递性。对象转换为有序字节流,以便在网络上传输…

Apache Doris (四十四): Doris数据更新与删除 - Delete 数据删除

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹哥教你大数据个人主页-哔哩哔哩视频 目录

在 Python 脚本中设置环境变量

环境变量是与系统进程交互的一种深入方式&#xff1b; 它允许用户获得有关系统属性、路径和已经存在的变量的更详细信息。 我们如何使用环境变量 如上所述&#xff0c;环境变量促使我们与系统进程进行交互。 我们可以使用环境变量来访问系统中的所有变量和键。 为此&#xff…

Spring中构造注入详解

目录 一、构造注入是什么 二、构造注入重载 一、构造注入是什么 书接上回&#xff0c;我们已经知道了setter注入是什么了&#xff0c;这里的构造注入也就很好理解了。构造注入也就是Spring通过调用类对象中的构造方法来进行注入。接下来利用代码演示构造注入 1&#xff09;先…

Elasticsearch系列组件:Beats高效的日志收集和传输解决方案

Elasticsearch 是一个开源的、基于 Lucene 的分布式搜索和分析引擎&#xff0c;设计用于云计算环境中&#xff0c;能够实现实时的、可扩展的搜索、分析和探索全文和结构化数据。它具有高度的可扩展性&#xff0c;可以在短时间内搜索和分析大量数据。 Elasticsearch 不仅仅是一个…

上海亚商投顾:沪指震荡调整 转基因概念股逆势大涨

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日低开低走&#xff0c;深成指、创业板指均跌超1%&#xff0c;双双创出年内新低。转基因概念股逆势大涨…

C语言初学者工具选择:vscode + MSYS2 + cmake 搭建 C环境

文章目录 前言1. MSYS2 安装1. 下载安装包2. 安装3. pacman 换清华大学源4. 安装 mingw-w64 toolchain 和 cmake ninja5. 将 toolchain 加入系统环境变量 2. 设置 vscode1. 必要的插件2. 一个简单的 vscode cmake 项目 最后C数据结构与算法CMake 前言 网上关于使用 vscode 配…

Leetcode刷题详解——无重复字符的最长子串

1. 题目链接&#xff1a;3. 无重复字符的最长子串 2. 题目描述&#xff1a; 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc"&#xff0c;所…

C++11(包装器)

目录 一、function包装器 1、概念 2、function的引入 3、function 1、对函数指针包装 2、对函数对象进行包装 3、对lambda表达式进行包装 4、对类的成员函数进行包装 二、bind包装器 1、概念 2、bind 1、绑定全局函数 2、绑定成员函数 3、参数调换顺序 一、functi…

pinia下载使用时报错如何解决?

报错 可能是因为pnpm下载的时候版本出现了问题 更新pnpm的版本 一、windowr打开终端 输入pnpm -v检查是否是最新版本 如果是8.6.2的话 就更新 更新步骤如下&#xff1a; 二&#xff1a;打开pnpm下载的网盘位置 我的是在c盘 找到里面的用户文件夹 点击选择dell里面的App data文…

C语言 内存

内存分配 内存分配的类型 C/C中内存分为5个区&#xff0c;分别为栈区、堆区、全局/静态存储区、常量存储区、代码区 静态内存分配&#xff1a;编译时分配&#xff0c;包括全局、静态全局、静态局部三种变量。 动态内存分配&#xff1a;运行时分配&#xff0c;包括栈&#x…

21天学会C++:Day15----STL简介

CSDN的uu们&#xff0c;大家好。这里是C入门的第十五讲。 座右铭&#xff1a;前路坎坷&#xff0c;披荆斩棘&#xff0c;扶摇直上。 博客主页&#xff1a; 姬如祎 收录专栏&#xff1a;C专题 目录 1. 什么是STL 2. STL的版本 3.STL的六大组件 4. STL的重要性 5. 如何学…

二叉树实现表达式求值(C++)

用二叉树来表示表达式&#xff0c;树的每一个节点包括一个运算符和运算数。代数表达式中只包含&#xff0c;-&#xff0c;*&#xff0c;/&#xff0c;&#xff08;&#xff0c;&#xff09;和一位整数且没有错误。按照先括号&#xff0c;再乘除&#xff0c;后加减的规则构造二叉…

【算法设计zxd】第6章 回溯法

目录 6.1 回溯法的设计技术 &#xff1a; 四皇后问题 回溯法&#xff1a; 算法框架&#xff1a; 思考题&#xff1a; 回溯算法的适用条件 【例6-1】求满足下列不等式的所有整数解&#xff1a; 6.2回溯算法的经典例题 【例6-2】装载问题  问题分析 计算模型  算法设计与描…

selenium多窗口、多iframe切换、alert、3种等待

1、多标签/多窗口之间的切换 场景&#xff1a; 在页面操作过程中有时候点击某个链接会弹出新的窗口&#xff0c;这时就需要切换到新打开的窗口上进行操作。这种情况下&#xff0c;需要识别多标签或窗口的情况。 操作方法&#xff1a; switch_to.window()方法&#xff1a;切换…

【AFL学习笔记(一)】简单的使用AFL进行漏洞挖掘测试

首先声明一点&#xff0c;ALF都是在Linux系统上运行 本文使用的是Ubuntu 20.4 版本进行演示 Step 1 下载afl-2.52b 官网地址afl2.52b 直接下载地址直接下载地址 下载完成之后在Ubuntu系统上进行解压&#xff1a; tar -afl-2.52b.tgzStep 2 创建测试用例 ①&#xff1a;创…

YOLOv5-训练自己的VOC格式数据集(VOC、自建数据集)

YOLOv5&#xff1a;训练自己的 VOC 格式数据集 1. 自定义数据集 1.1 环境安装 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple注意&#xff1a; 安装 lxmlPillow 版本要低于 10.0.0&#xff0c;解释链接: module ‘PIL.Image’ has no attri…

Amazon图片下载器:利用Scrapy库完成图像下载任务

概述 本文介绍了如何使用Python的Scrapy库编写一个简单的爬虫程序&#xff0c;实现从Amazon网站下载商品图片的功能。Scrapy是一个强大的爬虫框架&#xff0c;提供了许多方便的特性&#xff0c;如选择器、管道、中间件、代理等。本文将重点介绍如何使用Scrapy的图片管道和代理…

vue 使用crypto.js解密后,用JSON.parse转义报错非空白格解决办法

问题&#xff1a; 用JSON.parse转义crypto解密后的json字符串会发生错误。如图&#xff1a; 原因&#xff1a; 那是因为crypto自己加了一些未可见的字符&#xff0c;所以用正常的JSON.parse(xxxx)会报错。 解决办法&#xff1a; JSON.parse(xxxx.replace(/[\u0000-\u001F\u…