深入解析代理模式:静态代理、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 标准库提供的算法。并行算法由并发运行时中的现有功能组成。 若要对数据源操作进行并行化,一个必要步骤是将源分区为可由多个线程同时访问的多个部分。 分区程序将指定并行算法应如何在线…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...

大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...

2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...

Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...

无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...

抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...