【设计模式】单例模式 在java中的应用
文章目录
- 引言
- 什么是单例模式
- 单例模式的应用场景
- 单例模式的优缺点
- 优点
- 缺点
- 单例模式的基本实现
- 饿汉式单例模式
- 懒汉式单例模式
- 双重检查锁定
- 静态内部类
- 枚举单例
- 单例模式的线程安全问题
- 多线程环境下的单例模式
- 线程安全的实现方式
- 1. **懒汉式单例模式(线程不安全)**
- 2. **懒汉式单例模式(线程安全,使用同步方法)**
- 3. **双重检查锁定**
- 4. **静态内部类**
- 5. **枚举单例**
- 单例模式的序列化与反序列化
- 序列化导致的问题
- 如何防止反序列化破坏单例
- 单例模式的反射攻击
- 反射攻击导致的问题
- 如何防止反射破坏单例
- 使用枚举类型防止反射和序列化攻击
- 单例模式的实际应用案例
- 数据库连接池管理
- 日志管理
- 配置文件管理
- 总结
- 单例模式的最佳实践
- 单例模式的使用建议
引言
什么是单例模式
单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。单例模式通过控制实例化过程来避免创建多个实例,从而节省资源并确保全局状态的一致性。
在 Java 中,实现单例模式的核心思想是私有化构造方法,并通过一个公共的静态方法来返回类的唯一实例。
单例模式的应用场景
单例模式适用于以下场景:
- 资源管理器:如线程池、数据库连接池等,这些资源通常是重量级的,频繁创建和销毁会带来性能开销,因此需要一个全局唯一的实例来管理这些资源。
- 配置管理:应用程序的配置文件通常是全局唯一的,使用单例模式可以确保配置的唯一性和一致性。
- 日志记录器:日志记录器在整个应用程序中通常是唯一的,使用单例模式可以确保日志记录的统一性和线程安全性。
- 缓存:缓存数据通常需要全局唯一的实例来管理,以便在不同的地方访问和修改缓存时保持一致性。
单例模式的优缺点
优点
- 控制实例数量:确保一个类只有一个实例,避免了实例的重复创建,节省系统资源。
- 全局访问点:提供一个全局访问点,使得访问该实例变得简单。
- 延迟加载:某些实现方式(如懒汉式单例)可以实现延迟加载,即在需要时才创建实例,从而提高系统性能。
缺点
- 不易扩展:由于单例类的构造方法是私有的,继承和扩展变得困难。
- 隐藏依赖关系:单例模式隐藏了类之间的依赖关系,增加了代码的复杂性和维护难度。
- 多线程问题:在多线程环境下实现单例模式时,需要考虑线程安全问题,否则可能会创建多个实例。
单例模式的基本实现
饿汉式单例模式
饿汉式单例模式在类加载时就创建实例,确保类在第一次引用时就已经实例化。
public class HungrySingleton {// 类加载时就创建实例private static final HungrySingleton instance = new `();// 私有构造方法,防止外部实例化private HungrySingleton() {}// 提供公共的静态方法获取实例public static HungrySingleton getInstance() {return instance;}
}
优点:
- 实现简单。
- 线程安全,因为实例在类加载时就创建了。
缺点:
- 如果实例占用资源较多且未被使用,会造成资源浪费。
懒汉式单例模式
懒汉式单例模式在第一次需要使用实例时才创建,避免了资源浪费。
public class LazySingleton {// 静态变量保存单例实例private static LazySingleton instance;// 私有构造方法,防止外部实例化private LazySingleton() {}// 提供公共的静态方法获取实例public static LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}
}
优点:
- 延迟加载,只有在需要时才创建实例。
缺点:
- 线程不安全,多线程环境下可能会创建多个实例。
双重检查锁定
双重检查锁定在懒汉式单例模式的基础上,使用同步块和双重检查机制来保证线程安全。
public class DoubleCheckedLockingSingleton {// volatile 确保 instance 的可见性和有序性private static volatile DoubleCheckedLockingSingleton instance;// 私有构造方法,防止外部实例化private DoubleCheckedLockingSingleton() {}// 提供公共的静态方法获取实例public static DoubleCheckedLockingSingleton getInstance() {if (instance == null) {synchronized (DoubleCheckedLockingSingleton.class) {if (instance == null) {instance = new DoubleCheckedLockingSingleton();}}}return instance;}
}
优点:
- 线程安全。
- 延迟加载,性能较好。
缺点:
- 实现较为复杂,需要理解 volatile 关键字和双重检查机制。
静态内部类
静态内部类方式利用 JVM 类加载机制来保证线程安全,同时实现延迟加载。
public class StaticInnerClassSingleton {// 私有构造方法,防止外部实例化private StaticInnerClassSingleton() {}// 静态内部类private static class SingletonHolder {private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();}// 提供公共的静态方法获取实例public static StaticInnerClassSingleton getInstance() {return SingletonHolder.INSTANCE;}
}
优点:
- 线程安全。
- 延迟加载。
- 实现简单,利用 JVM 的类加载机制,避免了同步开销。
缺点:
- 无法提前创建实例。
枚举单例
枚举单例利用枚举类型本身的特性来保证单例模式的实现,是最简单且最安全的实现方式。
public enum EnumSingleton {INSTANCE;// 可以添加其他方法public void someMethod() {// 方法实现}
}
优点:
- 线程安全。
- 防止反序列化破坏单例。
- 防止反射攻击。
缺点:
- 无法实现延迟加载(但通常不需要,因为 JVM 保证枚举类的唯一性)。
单例模式的线程安全问题
多线程环境下的单例模式
在多线程环境中,单例模式的实现需要特别注意线程安全问题。多个线程同时访问单例类的实例获取方法时,可能会导致创建多个实例,违背单例模式的初衷。为了确保单例模式在多线程环境下的正确性,需要采取一些措施来保证线程安全。
线程安全的实现方式
1. 懒汉式单例模式(线程不安全)
最简单的懒汉式单例实现并没有考虑线程安全,在多线程环境下可能会创建多个实例。
public class LazySingleton {private static LazySingleton instance;private LazySingleton() {}public static LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}
}
2. 懒汉式单例模式(线程安全,使用同步方法)
通过在 getInstance 方法上加 synchronized 关键字,确保每次只有一个线程能够执行该方法,从而保证线程安全。
public class SynchronizedLazySingleton {private static SynchronizedLazySingleton instance;private SynchronizedLazySingleton() {}public static synchronized SynchronizedLazySingleton getInstance() {if (instance == null) {instance = new SynchronizedLazySingleton();}return instance;}
}
优点:
- 简单易实现。
- 线程安全。
缺点:
- 每次调用
getInstance方法时都需要进行同步,性能开销较大。
3. 双重检查锁定
双重检查锁定在第一次检查实例是否为 null 时不加锁,只有在实例为 null 时才进行同步操作,从而减少了同步开销。
public class DoubleCheckedLockingSingleton {private static volatile DoubleCheckedLockingSingleton instance;private DoubleCheckedLockingSingleton() {}public static DoubleCheckedLockingSingleton getInstance() {if (instance == null) {synchronized (DoubleCheckedLockingSingleton.class) {if (instance == null) {instance = new DoubleCheckedLockingSingleton();}}}return instance;}
}
优点:
- 线程安全。
- 相比同步方法,性能更高。
缺点:
- 实现复杂,需要注意
volatile关键字的使用。
4. 静态内部类
利用 Java 的类加载机制,静态内部类在被调用时才会被加载,从而实现延迟加载和线程安全。
public class StaticInnerClassSingleton {private StaticInnerClassSingleton() {}private static class SingletonHolder {private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();}public static StaticInnerClassSingleton getInstance() {return SingletonHolder.INSTANCE;}
}
优点:
- 线程安全。
- 实现简单,延迟加载。
缺点:
- 无法防止反射攻击。
5. 枚举单例
枚举类型本身是线程安全的,并且枚举的实例是全局唯一的,可以防止反射和序列化导致的重新创建实例问题。
public enum EnumSingleton {INSTANCE;public void someMethod() {// some method}
}
优点:
- 线程安全。
- 防止反射和序列化导致的重新创建实例问题。
缺点:
- 枚举类型在某些情况下可能不适用(例如需要继承其他类)。
单例模式的序列化与反序列化
序列化导致的问题
在 Java 中,单例模式可能会由于序列化和反序列化而被破坏。具体来说,当一个单例对象被序列化到文件中,然后再从文件中反序列化回来时,会创建一个新的实例,这样就违反了单例模式的原则。
例如,考虑以下单例类:
import java.io.Serializable;public class Singleton implements Serializable {private static final long serialVersionUID = 1L;private static final Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
}
如果我们进行序列化和反序列化操作:
import java.io.*;public class SingletonSerializationTest {public static void main(String[] args) throws Exception {Singleton instanceOne = Singleton.getInstance();// 序列化对象到文件ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("singleton.ser"));out.writeObject(instanceOne);out.close();// 从文件中反序列化对象ObjectInputStream in = new ObjectInputStream(new FileInputStream("singleton.ser"));Singleton instanceTwo = (Singleton) in.readObject();in.close();System.out.println("instanceOne hashCode: " + instanceOne.hashCode());System.out.println("instanceTwo hashCode: " + instanceTwo.hashCode());}
}
输出可能会是两个不同的哈希码,表明反序列化创建了一个新的实例。
如何防止反序列化破坏单例
为了防止反序列化破坏单例,可以在单例类中实现 readResolve 方法。这个方法在反序列化时会被自动调用,返回当前的单例实例,从而确保反序列化不会创建新的实例。
import java.io.Serializable;public class Singleton implements Serializable {private static final long serialVersionUID = 1L;private static final Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}// 添加 readResolve 方法protected Object readResolve() {return getInstance();}
}
现在,如果我们再次运行序列化和反序列化操作,输出将会是相同的哈希码,表明反序列化没有创建新的实例:
import java.io.*;public class SingletonSerializationTest {public static void main(String[] args) throws Exception {Singleton instanceOne = Singleton.getInstance();// 序列化对象到文件ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("singleton.ser"));out.writeObject(instanceOne);out.close();// 从文件中反序列化对象ObjectInputStream in = new ObjectInputStream(new FileInputStream("singleton.ser"));Singleton instanceTwo = (Singleton) in.readObject();in.close();System.out.println("instanceOne hashCode: " + instanceOne.hashCode());System.out.println("instanceTwo hashCode: " + instanceTwo.hashCode());}
}
通过实现 readResolve 方法,可以确保序列化和反序列化过程中不会破坏单例模式,从而维护单例的唯一性。
单例模式的反射攻击
反射攻击导致的问题
Java 的反射机制允许在运行时动态地创建对象、调用方法和访问字段。通过反射,可以绕过私有构造函数,直接创建单例类的新实例,从而破坏单例模式。
例如,考虑以下单例类:
public class Singleton {private static final Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
}
使用反射可以创建新的实例:
Singleton instance1 = Singleton.getInstance();Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
Singleton instance2 = constructor.newInstance();System.out.println(instance1 == instance2); // 输出 false
如何防止反射破坏单例
为了防止反射攻击,可以在单例类的构造函数中加入防御措施,确保在构造函数被多次调用时抛出异常。
public class Singleton {private static final Singleton instance = new Singleton();private static boolean instanceCreated = false;private Singleton() {if (instanceCreated) {throw new RuntimeException("单例实例已经存在,不能创建多个实例");}instanceCreated = true;}public static Singleton getInstance() {return instance;}
}
在上述代码中,instanceCreated 标志用于检测是否已经创建过实例。如果构造函数被再次调用,则抛出异常,防止通过反射创建新的实例。
使用枚举类型防止反射和序列化攻击
使用枚举类型实现单例模式是防止反射和序列化攻击的最简单和最有效的方法。枚举类型在 Java 中是天然的单例,并且防止反射攻击和序列化攻击。
public enum EnumSingleton {INSTANCE;public void someMethod() {// some method}
}
枚举类型的单例不仅简单,而且可以防止反射和序列化导致的单例破坏问题。
单例模式的实际应用案例
数据库连接池管理
数据库连接池是一个典型的单例模式应用场景。通过单例模式,确保整个应用程序只存在一个数据库连接池实例,从而有效管理数据库连接资源。
public class DatabaseConnectionPool {private static DatabaseConnectionPool instance;private ConnectionPool pool;private DatabaseConnectionPool() {// 初始化连接池}public static synchronized DatabaseConnectionPool getInstance() {if (instance == null) {instance = new DatabaseConnectionPool();}return instance;}public Connection getConnection() {return pool.getConnection();}
}
日志管理
日志管理也是单例模式的一个常见应用。通过单例模式,确保整个应用程序使用同一个日志记录器实例,从而统一管理日志输出。
public class Logger {private static Logger instance;private Logger() {// 初始化日志配置}public static synchronized Logger getInstance() {if (instance == null) {instance = new Logger();}return instance;}public void log(String message) {// 记录日志}
}
配置文件管理
配置文件管理通常也使用单例模式,确保整个应用程序只加载一次配置文件,并提供统一的接口访问配置数据。
public class ConfigurationManager {private static ConfigurationManager instance;private Properties properties;private ConfigurationManager() {// 加载配置文件properties = new Properties();try (InputStream input = new FileInputStream("config.properties")) {properties.load(input);} catch (IOException ex) {ex.printStackTrace();}}public static synchronized ConfigurationManager getInstance() {if (instance == null) {instance = new ConfigurationManager();}return instance;}public String getProperty(String key) {return properties.getProperty(key);}
}
总结
单例模式的最佳实践
- 私有构造函数:确保构造函数是私有的,防止外部直接实例化。
- 静态方法获取实例:通过静态方法获取唯一的实例。
- 防止反射攻击:在构造函数中添加检查,防止反射攻击。
- 防止序列化破坏:实现
readResolve方法,防止反序列化创建新的实例。 - 线程安全:在多线程环境中,使用合适的方式(如双重检查锁定、静态内部类、枚举单例)确保线程安全。
单例模式的使用建议
- 资源管理:适用于需要全局管理的资源,如数据库连接池、日志记录器、配置文件等。
- 性能考虑:在性能敏感的应用中,确保单例的创建和访问是高效的。
- 避免过度使用:虽然单例模式有其优势,但过度使用可能导致代码难以测试和维护。在设计时应慎重考虑是否真的需要单例模式。
- 测试友好:在单元测试中,可以使用依赖注入或其他设计模式来替代单例,以便于测试。
通过遵循这些最佳实践和使用建议,可以在项目中有效地应用单例模式,确保其稳定性和可维护性。
相关文章:
【设计模式】单例模式 在java中的应用
文章目录 引言什么是单例模式单例模式的应用场景单例模式的优缺点优点缺点 单例模式的基本实现饿汉式单例模式懒汉式单例模式双重检查锁定静态内部类枚举单例 单例模式的线程安全问题多线程环境下的单例模式线程安全的实现方式1. **懒汉式单例模式(线程不安全&#…...
burp suite 8
声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&a…...
为什么在Java中super与this不能共存于子类构造器中,其中this起什么作用
在 Java 中,super 和 this 是两个关键字,它们在子类的构造器中有特定的用途和限制。 super 关键字: super 用于从父类(超类)访问成员(属性和方法)或者调用父类的构造方法。 在子类的构造器中&…...
Hypothesis:高效的 Python 测试工具
简介:Hypothesis 是一个强大的 Python 测试库,旨在自动生成各种测试案例,以帮助开发者发现潜在的边界问题和隐藏的错误。通过对输入数据进行智能化的探索,Hypothesis 能够为测试提供更全面的覆盖,避免遗漏一些极端或不…...
Terminus Calculator 计算原理分享
在《使命召唤:黑色行动 6》僵尸模式中,Terminus 关卡的研究办公室里有一个复杂的数学谜题需要解决。为了获得多相共振器,玩家需要计算出三个数字并输入电脑。虽然可以花费 5000 精华来获得答案,但使用 Terminus Calculator 可以更…...
Wwise 使用MIDI文件、采样音频
第一种:当采样音频只有一个文件的时候 1.拖入MIDI文件到Interactive Music Hierarchy层级 2.拖入采样音频到Actor-Mixer Hierarchy层级 3.勾选MIDI显示出面板,设置Root Note与采样音频音高相同,这里是C#5 4.播放测试,成功&…...
在CentOS上无Parallel时并发上传.wav文件的Shell脚本解决方案
在CentOS上无Parallel时并发上传.wav文件的Shell脚本解决方案 背景概述解决方案脚本实现脚本说明使用指南注意事项在CentOS操作系统环境中,若需并发上传特定目录下的.wav文件至HTTP服务器,而系统未安装GNU parallel工具,我们可通过其他方法实现此需求。本文将介绍一种利用Sh…...
【RocketMQ 源码分析(一)】设计理念与源码阅读技巧
RocketMQ 的设计理念与源码阅读技巧 一、设计理念二、源码设计三、源码阅读技巧 一直想仔细仔细看看这个 RocketMQ 的源码,学学它的设计思想和编码风格,没准在以后自己在设计和编码的时候有思考的方向。这是专栏的第一篇 —— 介绍下 RocketMQ 的一些设计…...
独立ip服务器有什么优点?
网站的性能和安全性直接影响到用户体验和业务发,独立IP服务器作为一种主流的托管方式,因其独特的优势而受到许多企业和个人站长的青睐。与共享IP相比,独立IP服务器到底有哪些优点呢? 使用独立IP的用户不必担心与其他网站共享同一…...
如何使用Python库连接Redis
1、redis-py 库封装一个 Redis 工具类可以帮助我们简化 Redis 的操作并提高代码的复用性和可维护性。 安装redis pip install redisimport redis import logginglogging.basicConfig(levellogging.INFO) logger logging.getLogger(__name__)class RedisUtils:def __init__(s…...
Vant UI +Golang(gin) 上传文件
前端基本用法:点击查看 实现代码: const afterRead (file) > {console.log(file);//set content-type to multipart/form-dataconst formData new FormData();formData.append("file", file.file);request.POST("/api/v1/users/up…...
【Unity高级】如何实现粒子系统的间歇式喷射
先看下要最终实现的效果: 代码如下: using UnityEngine; using System.Collections;public class ParticleBurstController : MonoBehaviour {private ParticleSystem _particleSystem; // 获取粒子系统public float burstDuration 2f; // 每次…...
通过linux命令获取自选股票价格及大盘涨跌幅
技术发展与数据获取需求 互联网与金融数据融合:随着互联网的普及和金融市场的数字化发展,金融数据的获取和分析变得更加便捷和重要。投资者希望能够及时、准确地获取股票价格和市场指数等信息,以便做出合理的投资决策。Linux 作为一种强大的操作系统,为数据获取和处理提供…...
透彻理解并解决Mockito模拟框架的单元测试无法运行的问题
本篇的实例基于Maven IDE (VS Code) 运行 在VS Code 运行的时候, 不需要在pom.xml 中添加任何插件就可以在测试类中看到如下的绿色按钮,单击就可以运行使用Mockito 注解 ExtendWith(MockitoExtension.class) 或是 Mockito 代码方式的测试。 不使用注…...
vue3字典数据的显示问题(使用hooks解决)
我们在使用 element-plus的时候,经常会使用一些字典数据, 在搜索框的时候,字典数数要使用 el-select el-option 来显示,当在table表格的时候,我们通常记录的是 字典数据的id , 又要把它改变成 字典数据的 name 属性 因…...
Elasticsearch 单节点安全配置与用户认证
Elasticsearch 单节点安全配置与用户认证 安全扫描时发现了一个高危漏洞:Elasticsearch 未授权访问 。在使用 Elasticsearch 构建搜索引擎或处理大规模数据时,需要启用基本的安全功能来防止未经授权的访问。本文将通过简单的配置步骤,为单节…...
二分查找(带图详解)
优选算法系列 文章目录 优选算法系列前言一、二分查找的思想二、算法使用小总结 三、代码实现四、二分查找拓展4.1、查找第一次出现的target小总结 4.2、target最后出现的位置小总结 五、代码总结 前言 在这篇博客中,我会给大家分享二分查找及其扩展。 这是链接-&…...
【Git】:标签管理
目录 理解标签 创建标签 操作标签 理解标签 标签的作用 标记版本:标签 tag ,可以简单的理解为是对某次 commit 的⼀个标识,相当于起了⼀个别名。例如,在项目发布某个版本的时候,针对最后⼀次 commit 起⼀个 v1.0 这样…...
物品识别 树莓派 5 YOLO v5 v8 v10 11 计算机视觉
0. 要实现的效果 让树莓派可以识别身边的一些物品,比如电脑,鼠标,键盘,杯子,行李箱,双肩包,床,椅子等 1. 硬件设备 树莓派 5 raspberrypi.com/products/raspberry-pi-5/树莓派官方摄…...
单片机软件工程师前景分析
单片机软件工程师的前景在2024年看起来是积极的。随着物联网(IoT)、自动化、智能设备等领域的快速发展,对于能够开发基于单片机(MCU)如STM32、ARM、51等嵌入式系统的软件工程师需求持续增长。这些工程师负责设计和实现…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...
