Java进阶--设计模式
设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样,项目中合理地运用设计模式可以完美地解决很多问题。
设计模式多种多样,这里参考设计模式简介,本篇主要介绍最常用的几种。
设计模式的分类
分类 | 核心目标 | 典型模式 |
---|---|---|
创建型模式 | 对象创建过程的抽象与优化 | 工厂模式、抽象工厂、单例、建造者、原型 |
结构型模式 | 对象与类的组织方式(组合结构优化) | 适配器、代理、装饰者、桥接、组合、外观、享元 |
行为型模式 | 对象间的交互与职责分配(通信流程优化) | 策略、观察者、责任链、模板方法、命令、状态、迭代器、中介者、备忘录、访问者 |
常用的设计模式
单例模式
单例模式(Singleton Pattern)是一种创建型设计模式,其核心目标是确保一个类仅有一个实例,并提供该实例的全局访问点。
特点:1.单例类只有一个实例对象。
2.单例对象必须由单例类创建。
3.对外提供一个访问该单例的全局访问点
核心实现方式
1. 饿汉式
-
特点:类加载时立即创建实例,线程安全但可能造成资源浪费。
public class EagerSingleton {// 类加载时初始化实例private static final EagerSingleton instance = new EagerSingleton();// 私有构造方法,防止外部实例化private EagerSingleton() {}public static EagerSingleton getInstance() {return instance;} }
2. 懒汉式
-
特点:延迟实例化,首次调用时创建对象,需处理多线程安全问题。
基础版(非线程安全):
public class LazySingleton {private static LazySingleton instance;private LazySingleton() {}public static LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}
}
同步方法版(线程安全但性能低):
public class SynchronizedSingleton {private static SynchronizedSingleton instance;private SynchronizedSingleton() {}public static synchronized SynchronizedSingleton getInstance() {if (instance == null) {instance = new SynchronizedSingleton();}return instance;}
}
3. 双重检查锁(Double-Checked Locking)
-
特点:延迟加载 + 线程安全 + 高性能,适用于多线程环境。
public class DCLSingleton {// 使用 volatile 防止指令重排序private static volatile DCLSingleton instance;private DCLSingleton() {}public static DCLSingleton getInstance() {if (instance == null) { // 第一次检查synchronized (DCLSingleton.class) { // 同步块if (instance == null) { // 第二次检查instance = new DCLSingleton();}}}return instance;}
}
举例:Runtime类
public class Runtime {private static Runtime currentRuntime = new Runtime();public static Runtime getRuntime() {return currentRuntime;}private Runtime() {}
}
jdk中提供的类,标准的单例模式应用。
工厂模式
工厂模式(Factory Pattern)是一种创建型设计模式,其核心思想是将对象的创建逻辑与使用逻辑分离,通过统一的工厂接口或类来实例化对象,从而降低代码耦合度并提升扩展性。
一、简单工厂模式
定义
-
核心:通过一个工厂类,根据传入的参数决定创建哪种具体产品对象。
-
适用场景:产品种类较少且创建逻辑简单。
// 1. 定义产品接口
interface Car {void drive();
}// 2. 具体产品实现
class SedanCar implements Car {@Overridepublic void drive() {System.out.println("驾驶轿车");}
}class SUVCar implements Car {@Overridepublic void drive() {System.out.println("驾驶SUV");}
}// 3. 简单工厂类
class CarFactory {public static Car createCar(String type) {switch (type.toLowerCase()) {case "sedan":return new SedanCar();case "suv":return new SUVCar();default:throw new IllegalArgumentException("未知的汽车类型");}}
}// 4. 使用示例
public class Client {public static void main(String[] args) {Car sedan = CarFactory.createCar("sedan");sedan.drive(); // 输出:驾驶轿车Car suv = CarFactory.createCar("suv");suv.drive(); // 输出:驾驶SUV}
}
二、工厂方法模式
定义
-
核心:定义抽象工厂接口,由子类决定具体实例化哪个类。每个产品对应一个工厂。
public interface Car {void run();
}public class Aodi implements Car {@Overridepublic void run() {System.out.println("奥迪汽车行驶");}
}public class Bmw implements Car {@Overridepublic void run() {System.out.println("宝马汽车行驶");}
}public interface CarFactory {Car createCar();
}public class AodiFactory implements CarFactory{@Overridepublic Car createCar() {return new Aodi();}
}public class BmwFactory implements CarFactory{@Overridepublic Car createCar() {return new Bmw();}
}public class Test {public static void main(String[] args) {CarFactory aodicarFactory = new AodiFactory();Car aodi = aodicarFactory.createCar();aodi.run();CarFactory bmwcarFactory = new BmwFactory();Car bmw = bmwcarFactory.createCar();bmw.run();}
}
一个产品对应一个工厂,奥迪车对应奥迪工厂,宝马车对应宝马工厂。
三、抽象工厂模式
定义
-
核心:提供一个接口,用于创建相关或依赖对象的家族,而无需指定具体类。
public interface AbstractFactory {Car getCar();Phone getPhone();
}public interface Car {void run();
}public interface Phone {void call();
}public class AodiFactory implements AbstractFactory{@Overridepublic Car getCar() {return new AodiCar();}@Overridepublic Phone getPhone() {return new AodiPhone();}
}public class AodiCar implements Car{@Overridepublic void run() {System.out.println("奥迪汽车行驶");}
}public class AodiPhone implements Phone{@Overridepublic void call() {System.out.println("奥迪手机打电话");}
}public class BmwFactory implements AbstractFactory{@Overridepublic Car getCar() {return new BmwCar();}@Overridepublic Phone getPhone() {return new BmwPhone();}
}public class BmwCar implements Car{@Overridepublic void run() {System.out.println("宝马汽车行驶");}
}public class BmwPhone implements Phone {@Overridepublic void call() {System.out.println("宝马手机打电话");}
}public class Test {public static void main(String[] args) {AbstractFactory aodiFactory = new AodiFactory();Car aodiCar = aodiFactory.getCar();Phone aodiphone = aodiFactory.getPhone();aodiCar.run();aodiphone.call();AbstractFactory bmwFactory = new BmwFactory();Car bmwCar = bmwFactory.getCar();Phone bmwPhone = bmwFactory.getPhone();bmwCar.run();bmwPhone.call();}
}
一个接口对应一个家族或者一个系列的东西,在这个案例中,就是奥迪工厂对应奥迪手机,奥迪车等等,宝马抽象工厂对应宝马手机和宝马车。
三种工厂模式对比
模式 | 核心区别 | 适用场景 |
---|---|---|
简单工厂 | 一个工厂类创建所有产品 | 产品类型少,逻辑简单 |
工厂方法 | 每个产品对应一个工厂类 | 需要灵活扩展产品类型 |
抽象工厂 | 创建多个相关产品组成的家族 | 需要保证产品族的兼容性 |
原型模式
原型模式(Prototype Pattern)是一种创建型设计模式,其核心思想是通过复制现有对象来创建新对象,而不是通过 new
关键字重新构造。
复制对象及其所有引用类型字段,创建完全独立的新对象。
class Address implements Cloneable {String city;public Address(String city) {this.city = city;}@Overridepublic Address clone() throws CloneNotSupportedException {return (Address) super.clone();}
}class User implements Cloneable {String name;Address address;public User(String name, Address address) {this.name = name;this.address = address;}// 深拷贝:递归复制引用类型字段@Overridepublic User clone() throws CloneNotSupportedException {User cloned = (User) super.clone();cloned.address = this.address.clone(); // 克隆Address对象return cloned;}
}// 使用示例
User user1 = new User("Alice", new Address("Beijing"));
User user2 = user1.clone();user2.address.city = "Shanghai";
System.out.println(user1.address.city); // 输出:Beijing(原对象未受影响)
优点 | 缺点 |
---|---|
提升性能,避免重复初始化 | 深拷贝实现复杂(需递归克隆所有引用对象) |
动态配置对象属性 | 需注意循环引用问题 |
绕过构造函数限制 | 对不支持克隆的类需额外处理(如实现接口) |
小结:原型模式通过复制现有对象高效创建新实例,尤其适用于对象初始化成本高或需要动态配置的场景。在实现时需注意 深拷贝与浅拷贝 的区别,避免因引用共享导致的数据不一致。合理使用原型模式,可以显著优化性能并简化复杂对象的创建逻辑。
代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,其核心思想是通过代理对象控制对原始对象的访问,在不修改原始类的前提下增强功能或限制访问。
代理模式的三种角色
-
抽象主题
定义真实主题和代理主题的公共接口 -
真实主题
实现业务逻辑的核心类 -
代理类
持有真实主题的引用,控制对真实主题的访问,并附加额外功能。
静态代理
手动编写代理类,代理类与真实类实现同一接口。
// 1. 抽象主题接口
interface UserService {void saveUser(String username);
}// 2. 真实主题
class UserServiceImpl implements UserService {public void saveUser(String username) {System.out.println("保存用户: " + username);}
}// 3. 静态代理类
class UserServiceProxy implements UserService {private UserService target;public UserServiceProxy(UserService target) {this.target = target;}public void saveUser(String username) {//通知System.out.println("[日志] 开始保存用户...");target.saveUser(username);//通知System.out.println("[日志] 用户保存完成");}
}// 使用示例
public class Client {public static void main(String[] args) {UserService realService = new UserServiceImpl();UserService proxy = new UserServiceProxy(realService);proxy.saveUser("Alice");}
}
一个代理类可以对某一类的目标提供代理
满足开闭原则(添加一类目标时,可以扩展添加一个新的代理类),
代码是写死的,不灵活
动态代理
jdk代理
创建一个代理对象生成器,实现InvocationHandler,重写invoke方法,这个方法会被代理对象动态调用,代理对象在运行时,被动态创建,可以代理任意的目标对象,提高灵活性。
注意被代理的目标对象,必须实现一个接口,在生成代理对象时,需要通过接口来获取目标对象信息。
底层实现原理利用反射机制。
/*抽象操作定义 卖东西*/
public interface Sell {void sell();
}//目标类
public class CarFactoryImpl implements Sell {@Overridepublic void sell() {System.out.println("汽车厂卖汽车");}}/*动态代理类代理类不需要实现与目标类相同的接口,这样就可以代理任意的目标类但是是有要求的,目标类必需实现接口,此种方式是动态代理的实现方式之一: jdk代理 是一种纯反射机制实现(动态获取目标类接口方法)*/
public class DynamicProxy implements InvocationHandler {Object object;//真实对象,接收任何的目标类对象public DynamicProxy(Object object) {this.object = object;}/*在代理类中调用目标类中的具体方法,动态的将代理动态对象,目标类中要调用的方法,及方法中的参数传递过来Method method 就是动态获取的真正要执行的方法*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("之前开启事务");method.invoke(object);System.out.println("之后提交事务");return proxy;}public Object getProxy(){return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);}
}public class Test {public static void main(String[] args) {CarFactoryImpl vip = new CarFactoryImpl();DynamicProxy dtproxy = new DynamicProxy(vip);//自己创建的代理类对象//这才是真正的创建动态代理对象 获取目标类所实现的接口Sell carfactory = (Sell)dtproxy.getProxy();carfactory.sell();//使用代理对象调用接口中的方法,获取当前调用的方法,最终调用invoke方法}
}
cglib代理
CGLib 采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
public class CarFactoryImpl {public void sell() {System.out.println("汽车厂卖汽车");}}import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/** 动态代理类*/
public class CGLibProxy implements MethodInterceptor {private Enhancer enhancer = new Enhancer();public Object getProxy(Class<?> clazz){ enhancer.setSuperclass(clazz); enhancer.setCallback(this); return enhancer.create(); } /** 拦截所有目标类方法的调用 * 参数: * obj 目标实例对象 * method 目标方法的反射对象 * args 方法的参数 * proxy 代理类的实例 */public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {//代理类调用父类的方法 System.out.println("开始事务"); Object result = proxy.invokeSuper(obj, args); System.out.println("关闭事务"); return result; }
}
public class Test {public static void main(String[] args) {CGLibProxy proxy = new CGLibProxy();CarFactoryImpl carFactory = (CarFactoryImpl) proxy.getProxy(CarFactoryImpl.class);carFactory.sell();}
}
要求目标类不能是final修饰,方法也不能是final修饰的,和static修饰的.
在spring框架中两种代理生成机制都实现了:
可以根据目标是否实现接口自动选择生成代理对象的方式,
默认采用cglib代理方式生成.
代理模式通过间接访问目标对象,实现了功能增强和访问控制,是解耦系统模块、提升灵活性的重要手段。选择代理类型时需注意:
-
静态代理:简单场景,代理类少。
-
JDK 动态代理:基于接口,适合代理多个方法。
-
CGLIB 代理:代理无接口的类,需注意性能与限制。
适配器模式
适配器模式(Adapter Pattern)是一种结构型设计模式,用于将不兼容的接口转换为客户端期望的接口,使得原本无法协同工作的类能够一起协作。其核心思想是通过一个“中间层”(适配器)解决接口不匹配问题,类似于现实中的电源转接头。
适配器模式的核心角色
角色 | 说明 |
---|---|
目标接口(Target) | 客户端期望的接口(如 XmlParser ),定义客户端调用的标准方法。 |
适配者(Adaptee) | 已存在的、需要被适配的接口或类(如 JsonParser ),提供实际功能但接口不兼容。 |
适配器(Adapter) | 实现目标接口,并持有适配者的引用,通过转换逻辑调用适配者的方法。 |
-
特点:通过组合持有适配者对象,更灵活且符合合成复用原则。
-
适用场景:适配者与目标接口差异较大,或需适配多个适配者。
// 目标接口
public interface XmlParser {void parseXml(String xml);
}// 适配者类
public class JsonParser {public void parseJson(String json) {System.out.println("解析JSON: " + json);}
}// 对象适配器(持有适配者引用,实现目标接口)
public class JsonToXmlAdapter implements XmlParser {private JsonParser jsonParser;public JsonToXmlAdapter(JsonParser jsonParser) {this.jsonParser = jsonParser;}public void parseXml(String xml) {String json = convertXmlToJson(xml); // 转换逻辑jsonParser.parseJson(json); // 调用适配者方法}private String convertXmlToJson(String xml) {//伪代码return "Json"+xml,}
}
测试
public class Test {public static void main(String[] args) {JsonParser jsonParser = new JsonParser();XmlParser xmlParser = new JsonToXmlAdapter(jsonParser);xmlParser.parseXml("<order id='123'/>"); // 输出:解析JSON: { ... }}
}
其他案例:
Java I/O 中的适配器:将字节流转换为字符流。
Spring MVC 的 HandlerAdapter:统一处理不同类型的控制器(如基于注解的 @Controller
和旧的 Controller
接口)。
小结:
适配器模式通过接口转换解决不兼容问题,是集成遗留代码或第三方库的利器。
使用建议:
-
优先选择对象适配器,更灵活且符合组合复用原则。
-
避免滥用适配器,若接口不匹配问题可通过重构解决,则无需引入适配器。
-
在框架设计、系统集成、多格式兼容等场景中,适配器模式能显著提升代码复用性和扩展性。
模版方法模式
模板方法模式(Template Method Pattern)是一种行为型设计模式,其核心思想是定义一个算法的骨架,将某些步骤延迟到子类实现,使得子类可以在不改变算法结构的情况下重新定义某些步骤的具体实现。
角色 | 说明 |
---|---|
抽象类(Abstract Class) | 定义算法的骨架(模板方法),包含具体步骤和抽象方法。 |
具体子类(Concrete Class) | 实现抽象类中的抽象方法,完成特定步骤的具体逻辑。 |
模板方法(Template Method) | 抽象类中定义的算法流程,通常为 final 方法,防止子类重写算法结构。 |
钩子方法(Hook Method) | 抽象类中可选的方法,子类可选择性覆盖,用于影响算法流程。 |
举个例子:客户去银行办事,一般要经过以下 4 个流程:取号、排队、办理具体业务、对银行工作人员进行评分等。但是去办理的业务可能不同,可以延迟到子类中实现。
public abstract class AbstractBank {//办理业务方法 -- 模板方法public void handle(){this.offerNumber();this.lineup();this.business();this.score();}//抽号public void offerNumber(){System.out.println("抽号");}//排队public void lineup(){System.out.println("排队");}//办理具体业务--抽象方法,由具体子类实现public abstract void business();//评分public void score(){System.out.println("评分");}
}/*转账业务类*/
public class TransferBusiness extends AbstractBank{//转账public void business() {System.out.println("我要转账");}}/*存钱业务*/
public class StoreBusiness extends AbstractBank{//办理的具体业务public void business() {System.out.println("我要存钱");}
}
public class Test {public static void main(String[] args) {StoreBusiness storeBusiness = new StoreBusiness();storeBusiness.handle();System.out.println("===================================");TransferBusiness transferBusiness = new TransferBusiness();transferBusiness.handle();}
}
其他案例:
Servlet 的生命周期
Servlet 的 service()
方法是一个模板方法,处理 HTTP 请求的通用流程,子类(如 HttpServlet
)通过重写 doGet()
、doPost()
实现具体逻辑。
小洁:
模板方法模式通过固定算法骨架和灵活步骤实现,在保证代码复用性的同时支持扩展。其关键点在于:
-
定义模板方法:使用
final
修饰确保算法结构不被破坏。 -
抽象步骤方法:子类必须实现差异逻辑。
-
钩子方法:提供可选扩展点,控制算法流程。
适用场景:
-
多个子类有共同行为,但部分步骤不同。
-
需要控制子类扩展方式,避免破坏核心流程。
注意事项:
-
避免过度使用继承,若算法步骤频繁变化,可考虑策略模式。
-
合理使用钩子方法,保持代码简洁。
策略模式
策略模式(Strategy Pattern)是一种行为型设计模式,其核心思想是定义一系列算法,封装每个算法,并使它们可以互相替换。策略模式让算法的变化独立于使用它的客户端,通过动态切换算法实现灵活扩展,同时遵循开闭原则(对扩展开放,对修改关闭)。
角色 | 说明 |
---|---|
策略接口(Strategy) | 定义算法的公共接口(如 PaymentStrategy ),所有具体策略必须实现该接口。 |
具体策略类(Concrete Strategy) | 实现策略接口,提供具体的算法实现(如支付宝支付、微信支付)。 |
上下文类(Context) | 持有策略对象,并委托具体策略执行算法(如订单支付处理类)。 |
案例:电商支付策略
//定义策略接口
interface PaymentStrategy {void pay(double amount);
}//实现具体策略类// 支付宝支付
class AlipayStrategy implements PaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("支付宝支付: " + amount + "元");}
}// 微信支付
class WechatPayStrategy implements PaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("微信支付: " + amount + "元");}
}//委托策略执行// 银行卡支付
class BankCardStrategy implements PaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("银行卡支付: " + amount + "元");}
}class OrderPayment {private PaymentStrategy paymentStrategy;// 设置支付策略public void setPaymentStrategy(PaymentStrategy paymentStrategy) {this.paymentStrategy = paymentStrategy;}// 执行支付public void executePayment(double amount) {if (paymentStrategy == null) {throw new IllegalStateException("未设置支付策略");}paymentStrategy.pay(amount);}
}//调用
public class Client {public static void main(String[] args) {OrderPayment order = new OrderPayment();// 使用支付宝支付order.setPaymentStrategy(new AlipayStrategy());order.executePayment(100.0); // 输出:支付宝支付: 100.0元// 切换为微信支付order.setPaymentStrategy(new WechatPayStrategy());order.executePayment(200.0); // 输出:微信支付: 200.0元}
}
总结
策略模式通过封装算法和动态切换策略,有效提升了系统的灵活性和可维护性。其核心优势在于:
-
解耦算法与业务逻辑:客户端仅依赖抽象策略接口。
-
简化单元测试:每个策略可独立测试。
-
符合开闭原则:新增策略无需修改现有代码。
适用场景:
-
系统需要多种算法变体,且需动态切换。
-
存在复杂条件分支,需消除大量
if-else
或switch
语句。 -
算法需要独立复用,或需隔离算法实现细节。
注意事项:
-
合理控制策略类数量,避免类膨胀。
-
优先使用组合而非继承,保持代码灵活性。
观察者模式
观察者模式(Observer Pattern)是一种行为型设计模式,用于建立对象间的一对多依赖关系,当一个对象(被观察者)的状态发生改变时,所有依赖它的对象(观察者)会自动收到通知并更新。
角色 | 说明 |
---|---|
被观察者(Subject) | 维护观察者列表,提供注册、注销和通知方法(如 addObserver() , notifyObservers() )。 |
观察者(Observer) | 定义更新接口(如 update() ),接收被观察者的状态变化通知。 |
具体被观察者(Concrete Subject) | 实现业务逻辑,状态变更时触发通知(如订单状态变化)。 |
具体观察者(Concrete Observer) | 实现 update() 方法,定义收到通知后的具体响应逻辑(如发送邮件、更新UI)。 |
案例:微信公众号发文,用户订阅
//抽象观察者
public interface Observer {void update(String message);}//抽象主题
public interface Subject {//增加订阅者public void attach(Observer observer);//删除订阅者public void detach(Observer observer);//通知订阅者更新消息public void notify(String message);
}//真实主体
public class SubscriptionSubject implements Subject {//储存订阅公众号的微信用户--观察者private List<Observer> weixinUserlist = new ArrayList();//增加订阅者@Overridepublic void attach(Observer observer) {weixinUserlist.add(observer);}//删除订阅者@Overridepublic void detach(Observer observer) {weixinUserlist.remove(observer);}//通知订阅者更新消息@Overridepublic void notify(String message) {for (Observer observer : weixinUserlist) {observer.update(message);}}
}//真实观察者
public class WeixinUser implements Observer{// 微信用户名private String name;public WeixinUser(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println(name + "-" + message);}}
调用
public class Test {public static void main(String[] args) {SubscriptionSubject mSubscriptionSubject=new SubscriptionSubject();//创建微信用户WeixinUser user1=new WeixinUser("张三");WeixinUser user2=new WeixinUser("李四");WeixinUser user3=new WeixinUser("王麻子");//订阅公众号mSubscriptionSubject.attach(user1);mSubscriptionSubject.attach(user2);mSubscriptionSubject.attach(user3);//公众号更新发出消息给订阅的微信用户mSubscriptionSubject.notify("文章更新了");}}
总结
观察者模式通过事件通知机制实现对象间的动态联动,是解耦复杂系统的有效工具。其核心价值在于:
-
松耦合设计:主题与观察者独立演化。
-
灵活扩展:动态增删观察者,无需修改主题。
-
事件驱动:支持实时响应和异步处理。
适用场景:
-
需要实现一对多的消息通知。
-
期望降低对象间的直接依赖。
-
需构建灵活、可扩展的事件处理系统。
注意事项:
-
控制通知频率,避免性能瓶颈。
-
合理处理异常,防止单个观察者失败影响整体流程。
-
结合具体需求选择同步或异步通知方式。
推荐小说:大话设计模式
相关文章:
Java进阶--设计模式
设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样࿰…...
同时启动俩个tomcat压缩版
下载解压tomcat压缩版 复制一份,换个名字 更改任意一个tomcat的配置文件用记事本打开 修改三个位置 1.<Server port"8005" shutdown"SHUTDOWN"> 2. <Connector port"8080" protocol"HTTP/1.1" …...
ZYNQ MPSOC之PL与PS数据交互DMA方式
ZYNQ MPSOC之PL与PS数据交互DMA方式 1 摘要 XILINX ZYNQ 以及 ZYNQ MPSOC主要优势在于异构 ARM+FPGA。其中非常关键的一点使用了 AXI 总线进行高速互联。而且这个 AXI 总线是开放给我们用户使用的。在前面的文章中我们详解了使用了AXI-HP方式PL到PS端进行数据交互。本文主要涉…...
Qwen3本地化部署,准备工作:SGLang
文章目录 SGLang安装deepseek运行Qwen3-30B-A3B官网:https://github.com/sgl-project/sglang SGLang SGLang 是一个面向大语言模型和视觉语言模型的高效服务框架。它通过协同设计后端运行时和前端编程语言,使模型交互更快速且具备更高可控性。核心特性包括: 1. 快速后端运…...
一种动态分配内存错误的解决办法
1、项目背景 一款2年前开发的无线网络通信软件在最近的使用过程中出现网络中传感器离线的问题,此软件之前已经使用的几年了,基本功能还算稳定。这次为什么出了问题。 先派工程师去现场调试一下,初步的结果是网络信号弱,并且有个别…...
golang接口和具体实现之间的类型转换
在 Go 语言中,如果你有一个接口类型的变量,并且你知道它的具体实现类型,你可以使用类型断言将其转换为具体类型。类型断言的语法是 value, ok : interfaceVar.(ConcreteType),其中 interfaceVar 是接口变量,ConcreteTy…...
独立站SaaS平台源码搭建全流程指南:从零到部署
一、什么是独立站SaaS? 独立站SaaS(Software as a Service)指通过自主搭建的云平台为用户提供软件服务,与第三方平台(如Shopify)相比,具有以下优势: 完全自主控制:可自…...
零基础学指针2
零基础学指针---大端和小端 零基础学指针---什么是指针 零基础学指针---取值运算符*和地址运算符& 零基础学指针---结构体大小 零基础学指针5---数据类型转换 零基础学指针6---指针数组和数组指针 零基础学指针7---指针函数和函数指针 零基础学指针8---函数指针数组…...
TM1668芯片学习心得二
一、该芯片包括的指令:显示模式设置命令、数据命令设置、地址命令设置、显示控制; 1、显示模式设置 2、数据命令设置 3、地址命令设置 4、显示控制...
[FPGA VIDEO IP] VCU
Xilinx H.264/H.265 Video Codec Unit IP (PG252) 详细介绍 概述 Xilinx LogiCORE™ IP H.264/H.265 Video Codec Unit(VCU,PG252)是一个专为 Zynq UltraScale MPSoC 设备设计的硬件加速视频编解码模块,支持 H.264(A…...
Git从入门到精通-第一章-基础概念
目录 为什么要版本控制? 版本控制系统 本地版本控制系统 集中化的版本控制系统 分布式版本控制系统 Git是什么? 直接记录快照 几乎所有操作都是本地执行 保证完整性 Git一般只添加数据 三种状态! Git的三种状态 Git的三个阶段…...
简单表管理
1.创建表(学生表,课程表,成绩表) --首先创建数据库 STUxxx CREATE DATABASE STU065; USE STU065; --创建学生表 CREATE TABLE SSS065(SNO CHAR(10) NOT NULL PRIMARY KEY, -- 学号SNAME VARCHAR(20) NOT NULL, -- 姓名DEPA VARCHAR(20), -- 系别AGE INT…...
C#静态类与单例模式深度解析(七):从原理到工业级应用实践
一、静态类:全局工具箱的设计艺术 1.1 静态类的本质特性 public static class MathUtils {// 静态字段(线程安全需自行处理)public static readonly double GoldenRatio = 1.618;// 静态方法public static double CircleArea(double radius){return Math.PI * radius * ra…...
2025年深圳杯-东三省联赛赛题浅析-助攻快速选题
深圳杯作为竞赛时长一个月,上半年度数模竞赛中难度最大的竞赛,会被各种省级竞赛、高校作为选拔赛进行选拔。本文为了能够帮助大家快速的上手该题目,将从涉及背景、解题所需模型、求解算法、实际求解中可能遇到的问题等详细进行描述࿰…...
springboot集成Lucene详细使用
以下是 Spring Boot 集成 Lucene 的详细步骤: 添加依赖 在 Spring Boot 项目的 pom.xml 文件中添加 Lucene 的依赖,常用的核心依赖和中文分词器依赖如下: <dependency><groupId>org.apache.lucene</groupId><artifac…...
【数据链路层】网络通信的“桥梁建设者”
目录 一、核心定位二、关键技术详解1. MAC地址体系2. 帧结构剖析(以太网V2为例)3. 典型协议对比 三、关键设备原理1. 交换机工作原理2. ARP协议流程 四、高级应用场景1. VLAN虚拟局域网2. 生成树协议(STP) 五、典型故障排查1. MAC…...
《多端统一的终极答案:X5内核增强版的渲染优化全解析》
跨端应用的需求呈爆发式增长,无论是电商购物、社交互动,还是金融理财类应用,都期望能够在不同平台上为用户提供一致且流畅的体验。而在这一过程中,跨端渲染技术成为了关键瓶颈。腾讯X5内核增强版的出现,犹如一道曙光&a…...
【MySQL数据库】事务
目录 1,事务的详细介绍 2,事务的属性 3,事务常见的操作方式 1,事务的详细介绍 在MySQL数据库中,事务是指一组SQL语句作为一个指令去执行相应的操作,这些操作要么全部成功提交,对数据库产生影…...
《Python实战进阶》No45:性能分析工具 cProfile 与 line_profiler
Python实战进阶 No45:性能分析工具 cProfile 与 line_profiler 摘要 在AI模型开发中,代码性能直接影响训练效率和资源消耗。本节通过cProfile和line_profiler工具,实战演示如何定位Python代码中的性能瓶颈,并结合NumPy向量化操作…...
intellij idea最新版git开启Local Changes
习惯了在idea的git插件里,查看项目已修改的文件,但是新版idea默认不展示了,用起来很难受。 参考网上教程开启方法如下: 1. 确保安装Git Modal Commit Interface插件并开启该插件 2. 在Advanced Settings开启Use Modal Commit In…...
C++ RAII 编程范式详解
C RAII 编程范式详解 一、RAII 核心概念 RAII(Resource Acquisition Is Initialization,资源获取即初始化) 是 C 的核心编程范式,通过将资源生命周期与对象生命周期绑定实现安全、自动化的资源管理。 核心原则: 资源…...
什么是美颜SDK?美颜SDK安卓与iOS端开发指南
在视频拍摄场景,一个出色的美颜SDK,正在悄然支撑起整个视觉体验体系。那么,什么是美颜SDK?它的底层原理、应用场景、核心功能有哪些?安卓与iOS平台又该如何开发与集成美颜SDK?本文将为你详细解析࿰…...
为什么沟通是设计传递和验证的关键
设计转移和验证流程是研发(R&D)规划与项目执行之间的关键桥梁。这一阶段确保设计能够准确转化为生产,将代价高昂的延误降至最低,并保证产品质量。最近,我有幸与乔希・古德曼(Josh Goodman)进…...
计算机考研精炼 操作系统
第 14 章 操作系统概述 14.1 基本概念 14.1.1 操作系统的基本概念 如图 14 - 1 所示,操作系统是计算机系统中的一个重要组成部分,它位于计算机硬件和用户程序(用户)之间,负责管理计算机的硬件资源,为用户和…...
多商户电商系统整套源码开源,支持二次开发,构建多店铺高效联动运营方案
在数字化浪潮席卷全球的今天,电商行业竞争愈发激烈,多商户电商平台凭借其独特的生态优势,成为众多企业和创业者的热门选择。一套优质的多商户电商系统不仅能为商家提供稳定的销售渠道,还能为平台运营者创造巨大的商业价值。分享一…...
MS31860T——8 通道串行接口低边驱动器
MS31860T 是一款 8 通道低边驱动器,包含 SPI 串口通信、 PWM斩波器配置、过流保护、短路保护、欠压锁定和过热关断功能, 芯片可以读取每个通道的状态。MS31860T 可以诊断开路的负载情况,并可以读取故障信息。外部故障引脚指示芯片的故障状态。…...
解决GoLand无法Debug的问题
文章目录 解决GoLand无法Debug的问题问题描述解决方案方法一:安装并替换Delve调试工具方法二:通过GoLand自动安装方法三:配置自定义Delve路径 验证解决方案常见问题排查总结 解决GoLand无法Debug的问题 问题描述 在使用GoLand进行Go语言开发…...
centos升级glibc
描述 参考的文章 基于CentOS更新 glibc - 解决 GLIBC_2.29‘ not found_glibc2.29-CSDN博客 执行步骤 # 下载资源 wget https://ftp.gnu.org/gnu/libc/glibc-2.34.tar.gztar xvf glibc-2.34.tar.gz 服务器上可以能会出现下载较慢的情况,可以再自己的电脑上下载&…...
【Unity】如何解决UI中的Button无法绑定带参数方法的问题
问题描述: 1.直接为Button绑定一个带参数方法,报错了。 解决办法: 将该方法通过另一个方法进行封装即可。...
回收铼树脂RCX-5143
Tulsimer RCX-5143 是一种专为回收铼(Re)设计的大孔弱碱阴离子交换树脂,其核心功能是从酸性浸出液中选择性吸附高铼酸根,并通过高效洗脱实现铼的富集与纯化。以下从技术参数、工艺应用、经济性及行业案例等维度展开分析࿱…...
蓝桥杯赛后总结
首先需要声明一下,编程小白博主参加的是第十六届蓝桥杯大赛(软件赛)C/C组。 个人感受而言,第十六届蓝桥杯软件赛C/C组是比较有难度的,特别是填空题,一共两道题,小白的我是一道填空题也不会做&a…...
PCB设计工艺规范(三)走线要求
走线要求 1.走线要求2.固定孔、安装孔、过孔要求3.基准点要求4.丝印要求 1.走线要求 印制板距板边距离:V-CUT 边大于 0.75mm,铣槽边大于0.3mm。为了保证 PCB 加工时不出现露铜的缺陷,要求所有的走线及铜箔距离板边:V-CUT边大于 0.75mm,铣槽边…...
第十节:文本编辑
理论知识 文本编辑器的基本概念:文本编辑器是用于创建和编辑文本文件的工具。在 Linux 系统中,常见的文本编辑器有 vi、vim、nano 等。vi 和 vim 编辑器:vi 是一款经典的文本编辑器,vim 是 vi 的增强版,提供了更多的功…...
【Hive入门】Hive性能优化:执行计划分析EXPLAIN命令的使用
目录 1 EXPLAIN命令简介 1.1 什么是EXPLAIN命令? 1.2 EXPLAIN命令的语法 2 解读执行计划中的MapReduce阶段 2.1 执行计划的结构 2.2 Hive查询执行流程 2.3 MapReduce阶段的详细解读 3 识别性能瓶颈 3.1 数据倾斜 3.2 Shuffle开销 3.3 性能瓶颈识别与优化 4 总结 在大…...
Spring AI应用系列——基于ARK实现多模态模型应用
ARK 在这里指的是阿里云推出的 AIGC 研发平台 ARK,是阿里云面向开发者和企业用户打造的一站式 AIGC(AI Generated Content,人工智能生成内容)开发平台。 1. 引言 本文将深入探讨 ARK Multi-Model 的实现原理、架构设计以及关键参…...
从边缘到云端:边缘计算与云计算的协同未来
在数字化转型的浪潮中,云计算和边缘计算作为两种重要的计算范式,正在深刻改变着我们的生活和工作方式。云计算以其强大的计算能力和数据存储能力,已经成为企业数字化转型的核心支撑;而边缘计算则凭借其低延迟和高效率的特点&#…...
基于策略模式实现灵活可扩展的短信服务架构
基于策略模式实现灵活可扩展的短信服务架构 引言 在企业级应用开发中,短信服务是不可或缺的基础功能之一。随着业务发展,我们可能需要接入多个短信服务提供商(如阿里云、腾讯云、第三方短信网关等),并能够在不修改核…...
安全指南 | MCP安全检查清单:AI工具生态系统的隐形守护者
随着大型语言模型(LLM)技术的迅猛发展,MCP(Model Context Protocol)已经成为连接AI模型与外部工具、数据源的关键桥梁。它为AI应用(如Claude Desktop、Cursor等)提供了更高效的集成体验…...
ChipCN IDE KF32 导入工程后,无法编译的问题
使用ChipON IDE for KungFu32 导入已有的工程是时,发现能够编译,但是点击,同时选择硬件调试时 没有任何响应。查看工程调试配置时,发现如下问题: 没有看到添加有启动配置,说明就是这里的问题了(应该是IDE的…...
Win下的Kafka安装配置
一、准备工作(可以不做,毕竟最新版kafka也不需要zk) 1、Windows下安装Zookeeper (1)官网下载Zookeeper 官网下载地址 (2)解压Zookeeper安装包到指定目录C:\DevelopApp\zookeeper\apache-zoo…...
Vue2 vs Vue2.7 深度对比
Vue2 vs Vue2.7 深度对比 前言 作为 Vue 生态中承前启后的重要版本,Vue2.7 在保留 Vue2 核心特性的同时,引入了 Vue3 的诸多创新设计。本文将深入解析二者差异,通过架构对比、代码实战和性能基准测试,为企业技术选型提供决策依据…...
WPF使用高性能图表
WPF高性能图表实现方案 一、WPF图表技术选型对比 技术方案优点缺点适用场景WPF原生控件无需第三方依赖,完全可控开发成本高,性能有限简单图表需求OxyPlot轻量级,跨平台,开源功能相对基础中小型应用LiveCharts现代API,支持动画复杂场景性能一般中…...
当算力遇上贫困补助:能否让补助精准到户?
目录 一、让"贫困画像"从模糊到高清 二、破解扶贫"三大世界难题" 三、算力扶贫路上的三座大山 算力应该温暖谁? 以往扶贫的画面是“扶贫干部背着米面油翻山越岭”,当算力发展到一定程度,会呈现出一种新的画面:农民伯伯用手机扫描…...
基于连接感知的实时困倦分类图神经网络
疲劳驾驶是导致交通事故的主要原因之一。脑电图(EEG)是一种直接从大脑活动中检测睡意的方法,已广泛用于实时检测驾驶员的睡意。最近的研究表明,使用基于脑电图数据构建的大脑连接图来预测困倦状态的巨大潜力。然而,传统的脑连接网络与下游预测…...
Set系列之HashSet源码分析:原理剖析与实战对比
引言:哈希集合的基石 1.1 集合框架的核心地位 数据存储的三大特性:唯一性、无序性、快速访问HashSet的市场占有率:Java集合框架中使用率TOP3(占日常开发场景的45%) 1.2 为什么需要深入理解HashSet? 隐藏…...
vscode vim插件操作查缺补漏
一.多光标编辑 在 VSCode 中使用 Vim 插件 (VSCodeVim) 实现多光标选择和同时编辑的常用方法: 1. 逐个添加匹配项 (推荐) 快捷键: CtrlD (Win/Linux) / CmdD (Mac)操作: 将光标放在想选中的单词上。重复按此快捷键,会依次选中下…...
Python 爬取微店商品列表接口(item_search)的实战指南
在电商数据分析、市场调研或竞品分析中,获取商品列表信息是常见的需求。微店作为知名的电商平台,提供了丰富的商品资源和相应的 API 接口。本文将详细介绍如何使用 Python 爬虫技术,通过微店的 item_search 接口根据关键词搜索商品列表&#…...
游戏性能测试
1. 分阶段,看目的,确定高中低三档测试机,最低档机的确定需要和客户端主程和制作人等共同确定 确定三档机的方式: 1. 要上线地区的top100,根据用户占比,划分出三档 2. 根据用研部门提供的数据,确…...
Webug4.0通关笔记06- 第8关CSV注入
目录 CSV注入漏洞 1.CSV漏洞简介 2.漏洞原理 (1)公式执行 (2)DDE机制 (3)OS命令执行 3.漏洞防御 第08关 CSV注入 1.打开靶场 2.修改源码 3.注入命令 4.导出excel表 5.打开excel表 CSV注入漏洞…...
最新DeepSeek-Prover-V2-671B模型 简介、下载、体验、微调、数据集:专为数学定理自动证明设计的超大垂直领域语言模型(在线体验地址)
DeepSeek-Prover-V2-671B模型 简介、下载、体验、微调、数据集:专为数学定理自动证明设计的超大垂直领域语言模型(在线体验地址) 体验地址:[Hugging Face 在线体验]https://huggingface.co/playground?modelIddeepseek-ai/DeepS…...