深入解析代理模式:静态代理、JDK 动态代理和 CGLIB 的全方位对比!
代理模式(Proxy Pattern)是一种结构型设计模式,它提供了对象的替身,即代理对象来控制对实际对象的访问。通过代理对象,可以在不修改目标对象的情况下,扩展或控制其功能。例如,代理模式可以用于延迟加载、权限控制、日志记录等场景。
🎯 核心要点:
- 代理对象:代理模式通过代理对象替代实际对象进行控制,代理对象和实际对象实现相同的接口。
- 控制访问:代理对象可以控制客户端与实际对象的交互,甚至对客户端的请求进行预处理或后处理。
- 延迟初始化:代理对象可以在需要的时候才创建实际对象,节省资源。
UML类图
Subject
:这是接口,定义了代理对象和实际对象都要实现的公共接口,包含方法 request()
。
RealSubject
:实现 Subject
接口的类,表示真正执行操作的对象。
Proxy
:同样实现了 Subject
接口,代理 RealSubject
对象,控制对 RealSubject
的访问
静态代理
静态代理是指在编译期就已经确定了代理类。我们必须手动创建代理类,并明确代理哪个对象。代理类与被代理类实现相同的接口,通过代理类来控制对实际对象的访问。
静态代理案例:银行账户管理
假设我们有一个银行账户管理系统,用户通过 BankAccount
类管理账户余额,BankAccountProxy
作为代理类,添加了权限控制功能,只有拥有特定权限的用户才能执行账户操作
。
案例场景:
- 实际对象:
BankAccount
负责执行账户的具体操作(如查询余额)。 - 代理对象:
BankAccountProxy
负责控制对BankAccount
的访问,确保只有权限用户可以操作账户。
静态代理代码实现
Step 1: 定义接口
// Subject 接口
public interface BankAccount {void deposit(double amount);void withdraw(double amount);double getBalance();
}
Step 2: 实现具体的银行账户类
// RealSubject 实现类
public class RealBankAccount implements BankAccount {private double balance;public RealBankAccount(double initialBalance) {this.balance = initialBalance;}@Overridepublic void deposit(double amount) {balance += amount;System.out.println("Deposited " + amount + ", new balance is " + balance);}@Overridepublic void withdraw(double amount) {if (amount <= balance) {balance -= amount;System.out.println("Withdrew " + amount + ", new balance is " + balance);} else {System.out.println("Insufficient funds.");}}@Overridepublic double getBalance() {return balance;}
}
Step 3: 实现代理类
// Proxy 类
public class BankAccountProxy implements BankAccount {private RealBankAccount realBankAccount;private String userRole;public BankAccountProxy(RealBankAccount realBankAccount, String userRole) {this.realBankAccount = realBankAccount;this.userRole = userRole;}@Overridepublic void deposit(double amount) {if (userRole.equals("Admin")) {realBankAccount.deposit(amount);} else {System.out.println("Access denied: You don't have permission to deposit.");}}@Overridepublic void withdraw(double amount) {if (userRole.equals("Admin")) {realBankAccount.withdraw(amount);} else {System.out.println("Access denied: You don't have permission to withdraw.");}}@Overridepublic double getBalance() {return realBankAccount.getBalance();}
}
Step 4: 测试代理类
public class Client {public static void main(String[] args) {// 创建真实对象和代理对象RealBankAccount realAccount = new RealBankAccount(1000);BankAccount proxyAccount = new BankAccountProxy(realAccount, "User");// 测试代理访问proxyAccount.deposit(500); // 访问受限proxyAccount.withdraw(300); // 访问受限// 以 Admin 身份访问BankAccount adminAccount = new BankAccountProxy(realAccount, "Admin");adminAccount.deposit(500); // 成功存款adminAccount.withdraw(300); // 成功取款}
}
输出结果:
Access denied: You don't have permission to deposit.
Access denied: You don't have permission to withdraw.
Deposited 500.0, new balance is 1500.0
Withdrew 300.0, new balance is 1200.0
解释:
- 权限控制:
BankAccountProxy
控制了对RealBankAccount
的访问,只有拥有 Admin 权限的用户才能操作账户。 - 灵活扩展:通过代理类,我们可以在不修改
RealBankAccount
的前提下,灵活地添加权限控制功能。
动态代理(JDK 动态代理)
动态代理是在运行时动态生成代理类,而不是在编译时确定。动态代理可以通过反射机制自动生成代理对象,而无需手动编写代理类。
动态代理案例:银行账户管理(JDK 动态代理)
在 动态代理 中,代理类是在运行时动态生成的。Java 提供了 java.lang.reflect.Proxy
类和 InvocationHandler
接口来实现动态代理。
案例场景:
和静态代理案例类似,我们还是使用 BankAccount
管理账户,但是通过 JDK 动态代理 来动态生成代理类,代理类控制用户的操作权限,并记录日志
。
动态代理代码实现
Step 1: 定义接口(与静态代理相同)
// Subject 接口
public interface BankAccount {void deposit(double amount);void withdraw(double amount);double getBalance();
}
Step 2: 实现具体的银行账户类(与静态代理相同)
// RealSubject 实现类
public class RealBankAccount implements BankAccount {private double balance;public RealBankAccount(double initialBalance) {this.balance = initialBalance;}@Overridepublic void deposit(double amount) {balance += amount;System.out.println("Deposited " + amount + ", new balance is " + balance);}@Overridepublic void withdraw(double amount) {if (amount <= balance) {balance -= amount;System.out.println("Withdrew " + amount + ", new balance is " + balance);} else {System.out.println("Insufficient funds.");}}@Overridepublic double getBalance() {return balance;}
}
Step 3: 实现 InvocationHandler
接口
InvocationHandler
是动态代理的核心,通过 invoke()
方法拦截对目标对象的方法调用。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class BankAccountInvocationHandler implements InvocationHandler {private Object target;private String userRole;public BankAccountInvocationHandler(Object target, String userRole) {this.target = target;this.userRole = userRole;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (userRole.equals("Admin")) {System.out.println("Admin access granted.");return method.invoke(target, args); // 调用目标对象的方法} else {System.out.println("Access denied: You don't have permission to " + method.getName());return null;}}
}
Step 4: 动态代理测试
import java.lang.reflect.Proxy;public class Client {public static void main(String[] args) {// 创建真实对象RealBankAccount realAccount = new RealBankAccount(1000);// 创建动态代理对象BankAccount proxyAccount = (BankAccount) Proxy.newProxyInstance(realAccount.getClass().getClassLoader(),new Class[]{BankAccount.class},new BankAccountInvocationHandler(realAccount, "User"));// 测试代理访问proxyAccount.deposit(500); // 访问受限proxyAccount.withdraw(300); // 访问受限// 以 Admin 身份访问BankAccount adminAccount = (BankAccount) Proxy.newProxyInstance(realAccount.getClass().getClassLoader(),new Class[]{BankAccount.class},new BankAccountInvocationHandler(realAccount, "Admin"));adminAccount.deposit(500); // 成功存款adminAccount.withdraw(300); // 成功取款}
}
输出结果:
Access denied: You don't have permission to deposit
Access denied: You don't have permission to withdraw
Admin access granted.
Deposited 500.0, new balance is 1500.0
Admin access granted.
Withdrew 300.0, new balance is 1200.0
解释:
- 运行时生成代理类:通过
Proxy.newProxyInstance()
方法,动态生成代理类。 - 权限控制:动态代理可以在运行时灵活地进行权限控制,且不需要手动创建代理类。
CGLIB 动态代理
通过生成目标类的子类,并重写其中的方法来实现代理。它是在运行时生成的字节码,所以可以代理普通类和接口。代理类实际上是目标类的子类,并且会调用父类的方法。
- 依赖:需要导入
cglib
相关的库。 - 限制:由于 CGLIB 是通过继承实现的,所以不能代理
final
类或**final
方法**,因为这些无法被继承和重写。
CGLIB 依赖导入
在项目中,你需要下载CGLIB相关的所有JAR包,或者使用 Maven 或 Gradle 导入 cglib
依赖
Jar包下载地址:相关JAR点击下载
Maven 依赖:
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>
Gradle 依赖:
implementation 'cglib:cglib:3.3.0'
案例场景:银行账户管理(CGLIB 动态代理)
我们将基于前面的银行账户管理系统,使用 CGLIB 实现动态代理,控制用户操作权限并记录日志
。
场景:
- 实际对象:
BankAccount
是一个普通类,没有实现任何接口。 - 代理对象:使用 CGLIB 动态生成代理类,实现权限控制和日志功能
CGLIB 动态代理代码实现
Step 1: 创建 BankAccount
类
不再实现接口,这是一个普通类,CGLIB 可以代理这个类。
// RealSubject 实现类,普通类,没有实现接口
public class BankAccount {private double balance;public BankAccount(double initialBalance) {this.balance = initialBalance;}public void deposit(double amount) {balance += amount;System.out.println("Deposited " + amount + ", new balance is " + balance);}public void withdraw(double amount) {if (amount <= balance) {balance -= amount;System.out.println("Withdrew " + amount + ", new balance is " + balance);} else {System.out.println("Insufficient funds.");}}public double getBalance() {return balance;}
}
Step 2: 创建 MethodInterceptor
实现类
MethodInterceptor
是 CGLIB 代理的核心,通过重写 intercept()
方法来拦截目标类的方法调用
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class BankAccountMethodInterceptor implements MethodInterceptor {private String userRole;public BankAccountMethodInterceptor(String userRole) {this.userRole = userRole;}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {if (userRole.equals("Admin")) {System.out.println("Admin access granted.");return proxy.invokeSuper(obj, args); // 调用父类的原方法} else {System.out.println("Access denied: You don't have permission to " + method.getName());return null;}}
}
Step 3: 使用 Enhancer
动态生成代理类
CGLIB 使用 Enhancer
类来生成代理对象,Enhancer
会生成一个目标类的子类,并将方法调用委托给 MethodInterceptor
。
import net.sf.cglib.proxy.Enhancer;public class Client {public static void main(String[] args) {// 创建 Enhancer 对象Enhancer enhancer = new Enhancer();enhancer.setSuperclass(BankAccount.class); // 设置代理目标类enhancer.setCallback(new BankAccountMethodInterceptor("User")); // 设置拦截器// 创建代理对象BankAccount proxyAccount = (BankAccount) enhancer.create(new Class[]{double.class}, new Object[]{1000.0});// 测试代理访问proxyAccount.deposit(500); // 访问受限proxyAccount.withdraw(300); // 访问受限// 以 Admin 身份访问enhancer.setCallback(new BankAccountMethodInterceptor("Admin"));BankAccount adminAccount = (BankAccount) enhancer.create(new Class[]{double.class}, new Object[]{1000.0});adminAccount.deposit(500); // 成功存款adminAccount.withdraw(300); // 成功取款}
}
输出结果:
Access denied: You don't have permission to deposit
Access denied: You don't have permission to withdraw
Admin access granted.
Deposited 500.0, new balance is 1500.0
Admin access granted.
Withdrew 300.0, new balance is 1200.0
解释:
- 动态生成代理类:通过
Enhancer
类,动态生成了BankAccount
类的代理对象。 - 权限控制:
MethodInterceptor
控制了对目标方法的调用,只有具有 Admin 权限的用户才能执行操作。 - 日志功能:代理类在执行目标方法前,打印日志信息。
CGLIB 动态代理的优缺点
优点:
- 支持无接口类的代理:CGLIB 能够代理普通类,不要求目标类必须实现接口,这比 JDK 动态代理更灵活。
- 性能高:相比 JDK 动态代理,CGLIB 生成的代理类性能更高,尤其是在大量调用代理方法的场景下。
- 透明性:客户端无需修改,代理类的生成是透明的。
缺点:
- 不能代理
final
类和方法:由于 CGLIB 代理是通过生成子类实现的,因此无法代理final
类和final
方法。 - 依赖第三方库:CGLIB 是一个外部库,增加了项目的依赖复杂度。
总结:CGLIB 动态代理的特点
- 代理普通类:CGLIB 允许代理没有实现接口的类,这比 JDK 动态代理更加灵活。
- 通过继承实现代理:CGLIB 生成目标类的子类,并重写目标方法来实现代理。
- 应用场景广泛:CGLIB 动态代理适用于需要代理普通类、且调用频繁的场景。
🎯 Spring AOP 代理机制
Spring AOP(Aspect-Oriented Programming,面向切面编程)是 Spring 框架中的核心特性之一,它通过代理对象来对目标对象的方法进行拦截,在方法执行前后加入额外的逻辑,如日志记录、权限验证、事务管理等。
Spring AOP 中使用了两种代理机制:
- JDK 动态代理(基于接口的代理)
- CGLIB 动态代理(基于子类的代理)
使用的代理类型
- JDK 动态代理:当目标类实现了接口时,Spring AOP 默认使用 JDK 动态代理来生成代理对象。
- CGLIB 动态代理:当目标类没有实现接口时,Spring AOP 会使用 CGLIB 来生成代理对象。
Spring AOP 如何选择代理机制
Spring 选择代理的规则:
- 如果目标对象实现了接口,Spring AOP 默认使用 JDK 动态代理。
- 如果目标对象没有实现接口,Spring AOP 使用 CGLIB 动态代理。
- 可以强制使用 CGLIB:即使目标对象实现了接口,也可以通过配置来强制使用 CGLIB 代理。
Spring AOP 动态代理应用场景
Spring AOP 的代理机制广泛应用于以下场景:
- 事务管理:通过代理对象,在方法执行时自动管理事务的开启和提交。
- 日志记录:在方法执行前后自动添加日志记录。
- 权限控制:通过代理对象,控制用户是否有权限调用某些方法。
- 缓存机制:在方法执行前,先检查缓存,如果缓存中存在结果则直接返回,否则执行目标方法并将结果存入缓存
三种代理类型的对比
下表详细对比了 静态代理、JDK 动态代理 和 CGLIB 动态代理 的不同点。
对比维度 | 静态代理 | JDK 动态代理 | CGLIB 动态代理 |
---|---|---|---|
实现方式 | 手动创建代理类 | 通过 Proxy 类和 InvocationHandler 动态生成 | 通过继承目标类,使用字节码生成子类 |
是否需要接口 | 是,需要代理类和目标类实现相同接口 | 是,必须代理实现了接口的类 | 否,不需要接口,直接代理类本身 |
代理类生成时间 | 编译时生成,代码已确定 | 运行时动态生成 | 运行时动态生成 |
实现复杂度 | 需要手动编写代理类,代码重复 | 较简单,自动生成代理类 | 复杂度较高,需要字节码生成库 |
方法调用方式 | 代理类直接调用目标类方法 | 代理对象通过 InvocationHandler 反射调用目标方法 | 通过字节码技术生成子类,直接调用父类方法 |
代理性能 | 性能较好,方法直接调用 | 性能较差,基于反射调用,反射开销大 | 性能较高,生成的子类直接调用父类方法 |
代理对象结构 | 代理对象和目标对象有相同的接口 | 代理对象和目标对象实现相同接口 | 代理对象是目标类的子类 |
应用场景 | 适用于代理数量少、简单的场景 | 适用于需要代理实现接口的场景 | 适用于没有实现接口的类,或者需要大量代理的场景 |
是否可代理 final 类 | 是 | 否,无法代理 final 类 | 否,无法代理 final 类 |
优点 | 实现简单,直观 | 灵活,可以代理接口,易于扩展 | 可代理普通类,性能较高,适用于没有接口的类 |
缺点 | 需要为每个目标类手动编写代理类,代码冗余 | 只能代理接口,基于反射调用性能较低 | 无法代理 final 类,依赖外部库,配置较复杂 |
总结:三种代理的特点和适用场景
- 静态代理:
- 特点:代理类由开发者手动编写,固定且已确定,代码较多、可维护性较低。
- 适用场景:代理类少、功能固定的场景,简单、容易实现。
- JDK 动态代理:
- 特点:只能代理实现了接口的类,通过反射调用目标方法,代理类在运行时生成,性能相对较低。
- 适用场景:目标对象实现了接口,尤其是需要动态代理多个接口的场景,如日志记录、权限控制等。
- CGLIB 动态代理:
- 特点:不要求目标类必须实现接口,使用字节码生成技术生成目标类的子类,性能高于 JDK 动态代理,但无法代理
final
类和final
方法。 - 适用场景:目标类没有实现接口,且代理调用频繁时使用,尤其适合对普通类的代理
- 特点:不要求目标类必须实现接口,使用字节码生成技术生成目标类的子类,性能高于 JDK 动态代理,但无法代理
相关文章:

深入解析代理模式:静态代理、JDK 动态代理和 CGLIB 的全方位对比!
代理模式(Proxy Pattern)是一种结构型设计模式,它提供了对象的替身,即代理对象来控制对实际对象的访问。通过代理对象,可以在不修改目标对象的情况下,扩展或控制其功能。例如,代理模式可以用于延…...

51单片机快速入门之独立按键
51单片机快速入门之独立按键 这里我们需要用上一个仿真软件,只因不想硬件焊接:PROTEUS DESIGN SUITE PROTEUS DESIGN SUITE: PROTEUS DESIGN SUITE是一款由LabCenter Electronics开发的电子设计自动化(EDA)软件,广泛应用于电气工程和电子工…...

设计模式之工厂模式(通俗易懂--代码辅助理解【Java版】)
文章目录 设计模式概述1、工厂模式概述1)特点:2)主要角色:3)工作流程:4)优点5)缺点6)适用场景 2、简单工厂模式(静态工厂模式)1) 在简单工厂模式中,有三个主要…...

速盾:高防 cdn 分布式防御攻击?
在当今数字化时代,网络安全问题日益凸显,各种网络攻击手段层出不穷。为了保护企业和个人的网络资产安全,高防 CDN(Content Delivery Network,内容分发网络)成为了一种重要的防御手段。其中,分布…...

Unity3D类似于桌面精灵的功能实现
前言: 由于最近在做游戏魔改,很多功能在游戏里面没法实现(没错,说的就是排行榜),所以准备用Unity3D开发一个类似于桌面精灵的功能部件,实现效果如下: PS:有需要定制的老…...

Audio Over IP的PTP时钟初探
Audio Over IP的PTP时钟初探 这几天参加省局举办的技术能手比赛,第一次接触并了解AOIP(Audio Over IP)相关的理论和实践相关的知识。其中AoIP的时钟同步采用的是IEEE 1588 标准的PTP(Precision Time Protocol)基于网络…...

【加密社】深入理解TON智能合约 (FunC语法)
king: 摘要:在TON(TheOpenNetwork)区块链平台中,智能合约扮演着举足轻重的角色。本文将通过分析一段TON智能合约代码 带领读者学习dict(字典)和list(列表)在FunC语言中的用法&#x…...

笔试强训day11
游游的水果大礼包 #include <iostream> #define int long longusing namespace std; int n, m, a, b;signed main() {cin>>n>>m>>a>>b;int ret 0;for(int x 0; x < min(n / 2, m); x) // 枚举 1 号礼包的个数{int y min(n - x * 2, (m - …...

移动应用开发与测试赛题
引言 在现代车载系统开发中,UI设计和编程实现同样重要。本文将分别探讨车载系统的UI设计任务和相关的编程任务,帮助开发者全面了解车载系统开发的各个方面。 第一部分:UI设计任务 任务1:绘制"左转向视频显示"模块界面…...

Qt常用控件——QLineEdit
文章目录 QLineEdit核心属性和信号基本示例正则表达式约束验证输入密码是否一致密码显示状态切换 QLineEdit核心属性和信号 QLineEdit用来表示单行输入,可以输入一段文本,但是不能替换 核心属性: 属性说明text输入框中的文本inputMask输入…...

(postman)接口测试进阶实战
1.内置和自定义的动态参数 内置的动态参数有哪些? ---{{$}}--是内置动态参数的标志 //自定义的动态参数 此处date.now()的作用就相当于上面的timestamp 2.业务闭环及文件接口测试 返回的url地址可以在网页中查询得到。 3. 常规断言,动态参数断言…...

R语言统计分析——功效分析(比例、卡方检验)
参考资料:R语言实战【第2版】 1、比例检验 当比较两个比例时,可使用pwr.2p.test()函数进行功效分析。格式为: pwr.2p.test(h, n, sig.level, power, alternative) 其中,h是效应值,n是各相同的样本量。效应值h的定义如…...

Leetcode 每日一题:Longest Increasing Path in a Matrix
写在前面: 今天我们继续看一道 图论和遍历 相关的题目。这道题目的背景是在一个矩阵当中找寻最长的递增数列长度。思路上非常好想,绝对和 DFS 相关,但是题目的优化要求非常高,对于语言和内存特性的考察特别丰富,如果是…...

ARCGIS PRO DSK MapTool
MapTool用于自定义地图操作工具,使用户能够在ArcGIS Pro中执行特定的地图交互操作。添加 打开MapTool1.vb文件,可以看到系统已经放出MapTool1类: Public Sub New()将 IsSketchTool 设置为 true 以使此属性生效IsSketchTool TrueSketchTyp…...

国网B接口 USC安防平台 海康摄像机配置
国网B接口海康摄像机配置介绍 如下以海康DS-NACN6432I-GLN摄像机为例,配置国网B接口设备接入流程,海康摄像机的固件版本为 V5.6.11 build 210109 210107。该设备为球机,支持国网B接口云台控制功能。图标编号可以对应二者的配置。 注意 同一…...

Win10安装.net FrameWork3.5失败解决方法
win10安装.net FrameWork3.5失败解决方法 已经好久没有来投稿了,实在最近业务缠身,忙的焦头烂额(呵~多么伟大的牛马) 但最近开发使用windows11实在是拉胯的不行,升级完就后悔,所以就一怒之下,重装了win10 可是,好家伙,我重装完遇到一个问题,就是在使用.Net Framework3.5,按照Mi…...

【pipenv】—— 虚拟环境管理工具近乎全面的总结
安装 pip install pipenv 使用和配置 设置虚拟环境文件创建在项目根目录 添加环境变量:WORKON_HOMEPIPENV_VENV_IN_PROJECT 创建虚拟环境时,自动换用指定的pip源 添加环境变量:PIPENV_TEST_INDEXhttps://pypi.tuna.tsinghua.edu…...

windows C++-并行编程-并行算法(五) -选择排序算法
并行模式库 (PPL) 提供了对数据集合并行地执行工作的算法。这些算法类似于 C 标准库提供的算法。并行算法由并发运行时中的现有功能组成。 在许多情况下,parallel_sort 会提供速度和内存性能的最佳平衡。 但是,当您增加数据集的大小、可用处理器的数量或…...

【系统架构设计师-2014年真题】案例分析-答案及详解
更多内容请见: 备考系统架构设计师-核心总结索引 文章目录 【材料1】问题1问题2【材料2】问题1问题2问题3【材料3】问题1问题2问题3【材料4】问题1问题2【材料5】问题1问题2问题3【材料1】 请详细阅读以下关于网络设备管理系统架构设计的说明,在答题纸上回答问题1和问题2。 …...

windows C++-并行编程-并行算法(三)-分区工作
并行模式库 (PPL) 提供了对数据集合并行地执行工作的算法。这些算法类似于 C 标准库提供的算法。并行算法由并发运行时中的现有功能组成。 若要对数据源操作进行并行化,一个必要步骤是将源分区为可由多个线程同时访问的多个部分。 分区程序将指定并行算法应如何在线…...

下载 llama2-7b-hf 全流程【小白踩坑记录】
1、文件转换 在官网 https://ai.meta.com/llama/ 申请一个账号,选择要下载的模型,会收到一个邮件,邮件中介绍了下载方法 执行命令 git clone https://github.com/meta-llama/llama.git ,然后执行 llama/download.sh,…...

Codeforces practice C++ 2024/9/11 - 2024/9/13
D. Mathematical Problem Codeforces Round 954 (Div. 3) 原题链接:https://codeforces.com/contest/1986/problem/D 题目标签分类:brute force,dp,greedy,implementation,math,two pointers…...

RabbitMQ创建交换机和队列——配置类 注解
交换机的类型 Fanout:广播,将消息交给所有绑定到交换机的队列。 Direct:订阅,基于RoutingKey(路由key)发送给订阅了消息的队列。 Topic:通配符订阅,与Direct类似,只不…...

proteus+51单片机+AD/DA学习5
目录 1.DA转换原理 1.1基本概念 1.1.1DA的简介 1.1.2DA0832芯片 1.1.3PCF8591芯片 1.2代码 1.2.1DAC8053的代码 1.2.2PCF8951的代码 1.3仿真 1.3.1DAC0832的仿真 1.3.2PFC8951的仿真 2.AD转换原理 2.1AD的基本概念 2.1.1AD的简介 2.1.2ADC0809的介绍 2.1.3XPT2…...

【Python机器学习】长短期记忆网络(LSTM)
目录 随时间反向传播 实践 模型的使用 脏数据 “未知”词条的处理 字符级建模(英文) 生成聊天文章 进一步生成文本 文本生成的问题:内容不受控 其他记忆机制 更深的网络 尽管在序列数据中,循环神经网络为对各种语言关系…...

【Go】使用Goland创建第一个Go项目
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...

STM32学习笔记(一、使用DAP仿真器下载程序)
我们想要使用32单片机,总共包含四个步骤: 1、硬件连接 2、仿真器配置 3、编写程序 4、下载程序 一、第一个问题(硬件连接):如何进行硬件连接,才能够启动32板子并能够下载程序呢? 答&#…...

储能运维管理云平台解决方案EMS能量管理系统
在储能行业蓬勃发展的今天,储能运维管理的重要性日益凸显。而储能运维管理云平台的出现,正为储能系统的稳定运行和高效管理注入了新的活力。 一、储能运维管理面临的挑战 传统的储能运维管理方式往往依赖人工巡检和现场操作,存在诸多问题。比…...

网络药理学:16、速通流程版
一、筛选疾病靶点 GeneCards 下载数据得到GeneCards-SearchResult.csv通过Relevance score≥1.0得到GeneCards.csv步骤2只保留Gene Symbol,即基因名这一列得到GeneCards_gene_names.csv OMIM 下载数据得到OMIM-Gene-Map-Retrieval.xlsx只保留Gene/Locus…...

P2515 [HAOI2010] 软件安装
~~~~~ P2515 [HAOI2010] 软件安装 ~~~~~ 总题单链接 思路 ~~~~~ 发现构成的图是一个森林和一些环。 ~~~~~ 对于森林,建一个虚点然后树形 D P DP DP 即可。 ~~~~~ 对于环,发现要么把这个环上的每一个点都选了,要么每一个都不选。所以可以先缩…...