当前位置: 首页 > news >正文

跟着GPT学设计模式之单例模式

单例设计模式(Singleton Design Pattern)一个类只允许创建一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫作单例设计模式,简称单例模式。

单例有几种经典的实现方式,它们分别是:饿汉式、懒汉式、双重检测、静态内部类、枚举。

单例模式解决的问题

  • 处理资源访问冲突,资源的访问因为并发带来的问题。通过限制类的实例化过程,单例模式确保在应用程序运行期间只会创建一个特定类的对象。这对于需要共享数据或资源的情况非常有用,避免了多个实例同时操作导致数据不一致或资源浪费的问题。
  • 表示全局唯一类,比如,配置信息类。单例模式提供了一个全局访问点,使得其他类可以轻松地访问该单例对象。这样可以方便地共享类的实例,避免了频繁地传递对象实例的麻烦。

带来的好处:

  • 在一些场景中能减少内存的使用和性能提升。
  • 解决资源访问互斥的问题。
  • 节省资源:由于单例模式只创建一个实例,可以节省系统资源,尤其是在需要频繁创建和销毁对象的场景下。
  • 维护一致性:单例模式可以确保数据和资源的一致性,因为只有一个实例进行操作,避免了多个实例之间的竞争和冲突。
  • 全局访问:单例模式提供了一个全局访问点,使得其他对象可以轻松地获取实例,方便了数据共享和交互。
  • 延迟实例化:单例模式可以延迟对象的实例化,只有在需要时才进行创建,提高了系统的性能和效率。

缺点:

  • 高耦合性:单例模式的实现通常需要在类中创建全局访问点,这导致了对象的使用者与单例类之间存在高度的耦合性。这样一来,当需要修改单例类时,可能需要修改引用该类的所有代码,增加了代码的维护难度。
  • 难以进行单元测试:由于单例模式在全局范围内共享实例,很难对单例对象进行模拟和替换,从而使得单元测试变得困难。单元测试应该是隔离的、独立的,而单例模式的全局特性会影响到测试结果,增加了测试的复杂性。
  • 对象生命周期过长:单例模式的对象在整个应用程序的生命周期中都存在,无法自动释放和回收。如果不正确地使用和管理单例对象,可能会导致内存泄漏或资源浪费的问题。
  • 不支持多线程并发访问:某些实现方式的单例模式在多线程环境下可能会出现并发访问的问题,需要进行额外的线程安全处理。例如,懒汉式需要在获取实例时进行同步处理,可能会影响性能。
  • 违反单一职责原则:单例模式通常承担了过多的职责,既要负责自身的逻辑功能,又要管理对象的生命周期和资源等。这样违反了单一职责原则,降低了代码的可读性和可维护性。

单例模式的实现

饿汉式

饿汉式是一种单例模式的实现方式,其特点是在类加载时就创建并初始化了单例对象,无论是否需要使用该对象。

  1. 类加载时即创建对象:在饿汉式中,单例对象的创建和初始化发生在类加载的过程中,因此在应用程序启动时就已经存在一个单例对象。
  2. 线程安全:饿汉式的实现方式保证了在多线程环境下的线程安全性。由于单例对象在类加载时就被创建,所以不存在多个线程同时访问和创建对象的情况,避免了并发访问导致的线程安全问题。
  3. 全局访问点:饿汉式通过静态变量提供了一个全局访问点,其他对象可以直接通过该变量获取单例对象,方便了对单例对象的使用和操作。
  4. 性能优化:饿汉式避免了每次获取单例对象时的实例化开销,因为对象在类加载时已经完成了实例化。这在某些场景下可以提高系统性能。

然而,饿汉式也存在一些缺点:

  1. 占用内存空间:由于在类加载时就创建了单例对象,所以该对象会一直存在于内存中,无论是否被使用。如果单例对象占用较大内存,可能会造成资源浪费。
  2. 强耦合性:饿汉式在类加载时就创建对象,导致单例对象与类的生命周期紧密耦合,难以灵活控制单例对象的创建和销毁。
  3. 延迟加载不支持:饿汉式无法实现延迟加载,即只有当需要使用单例对象时才进行实例化。这可能在某些场景下造成不必要的开销。

因此,在使用饿汉式时需要考虑以上优缺点,并根据具体需求进行选择。

package com.iluwatar.singleton;/*** Singleton class. Eagerly initialized static instance guarantees thread safety. 单例类,在类加载的时候,instance 静态实例就已经创建并初始化好了,所以,instance 实例的创建过程是线程安全的。*/
public final class IvoryTower {/*** Private constructor so nobody can instantiate the class.* 构造器私有,所以无法通过构造器创建这个类*/private IvoryTower() {}/*** Static to class instance of the class.* 静态变量初始化,jvm加载的时候就会执行*/private static final IvoryTower INSTANCE = new IvoryTower();/*** To be called by user to obtain instance of the class.* 通过这个方法获取这个类的实例* @return instance of the singleton.*/public static IvoryTower getInstance() {return INSTANCE;}
}

懒汉式

懒汉式是单例模式的另一种实现方式。与饿汉式不同,懒汉式在需要时才进行单例对象的创建和初始化,也就是延迟加载。

以下是懒汉式的一般实现方式:

  • 私有化构造方法:将单例类的构造方法声明为私有,防止外部代码通过直接实例化来创建对象。
  • 提供静态方法获取实例:通过一个静态方法来获取单例对象,在该方法内部进行懒加载的处理。
  • 延迟加载:在静态方法内部,先判断单例对象是否已经被创建,如果未创建,则进行对象的实例化操作。否则,直接返回已创建的对象。
  • 线程安全处理:因为懒汉式在需要时才创建对象,所以存在多线程环境下可能同时进入创建实例的判断逻辑的情况。因此,需要在静态方法中增加同步控制,保证只有一个线程可以创建实例。

懒汉式相对于饿汉式有一些优点:

  • 延迟加载:懒汉式可以在需要时才进行实例化,避免了在应用程序启动时就创建对象,从而减少了不必要的资源消耗。
  • 线程安全控制:通过在静态方法中增加同步控制,可以保证在多线程环境下的线程安全性。

然而,懒汉式也存在一些缺点:

  • 性能开销:由于需要进行同步控制,懒汉式在获取单例对象时可能会引入性能开销,特别是在高并发环境下。
  • 双重检查锁机制问题:懒汉式通常使用双重检查锁机制来实现延迟加载和线程安全。但这种方式在某些编程语言和平台下可能存在问题,导致无法正确实现线程安全性。

因此,在使用懒汉式时需要注意解决线程安全性问题,并根据具体需求和场景综合考虑是否选择懒汉式作为单例模式的实现方式。


/*** <p>Thread-safe Singleton class. The instance is lazily initialized and thus needs synchronization* mechanism.</p>懒汉式相对于饿汉式的优势是支持延迟加载。增加了类锁。**/
public final class ThreadSafeLazyLoadedIvoryTower {private static volatile ThreadSafeLazyLoadedIvoryTower instance;private ThreadSafeLazyLoadedIvoryTower() {// Protect against instantiation via reflectionif (instance != null) {throw new IllegalStateException("Already initialized.");}}/*** The instance doesn't get created until the method is called for the first time.实例不能初始化直到第一次调用完成,因为加了锁的。*/public static synchronized ThreadSafeLazyLoadedIvoryTower getInstance() {if (instance == null) {instance = new ThreadSafeLazyLoadedIvoryTower();}return instance;}
}

双重检测

双重检测(Double-Checked Locking)是一种在懒汉式中用于实现延迟加载和线程安全的机制。它是为了解决懒汉式在多线程环境下可能出现竞态条件(Race Condition)而引入的。

双重检测的基本原理如下:

  • 在静态方法中首先进行一次判断,如果单例对象已经被创建,则直接返回该对象,避免不必要的同步开销。
  • 如果单例对象尚未创建,则进入同步块。
  • 在同步块内部再次进行判断,确保只有一个线程可以创建单例对象。
  • 在同步块内部创建单例对象,并将其赋值给静态变量。
  • 最后,返回单例对象。

通过双重检测机制,可以减少对同步锁的使用,提高性能。

需要注意的是,在某些编程语言和平台下,双重检测锁机制可能存在问题,即所谓的双重检测锁失效问题,导致无法正确实现线程安全性。为了解决这个问题,可以使用volatile关键字来确保可见性,或者使用其他线程安全的机制来实现延迟加载。

总之,双重检测是一种在懒汉式中常用的实现方式,可以在一定程度上解决线程安全和性能的问题,但需要注意在具体的编程语言和平台上是否适用,并仔细考虑是否需要额外的机制来确保线程安全性。


/*** <p>Double check locking.</p>* 既支持延迟加载、又支持高并发的单例实现方式,也就是双重检测实现方式* <p>http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html</p>** <p>Broken under Java 1.4.</p>** @author mortezaadi@gmail.com*/
public final class ThreadSafeDoubleCheckLocking {private static volatile ThreadSafeDoubleCheckLocking instance;/*** private constructor to prevent client from instantiating.构造器私有防止客户端调用初始化*/private ThreadSafeDoubleCheckLocking() {// to prevent instantiating by Reflection call抛出异常来防止反射调用if (instance != null) {throw new IllegalStateException("Already initialized.");}}/*** Public accessor.** @return an instance of the class.*/public static ThreadSafeDoubleCheckLocking getInstance() {// local variable increases performance by 25 percent// Joshua Bloch "Effective Java, Second Edition", p. 283-284var result = instance;// Check if singleton instance is initialized. 检查单例是否初始化,如果初始化了就直接返回// If it is initialized then we can return the instance.if (result == null) {// It is not initialized but we cannot be sure because some other thread might have// initialized it in the meanwhile. 多线程并发可能同时创建实例,这里需要加锁。// So to make sure we need to lock on an object to get mutual exclusion.synchronized (ThreadSafeDoubleCheckLocking.class) {// Again assign the instance to local variable to check if it was initialized by some// other thread while current thread was blocked to enter the locked zone.// If it was initialized then we can return the previously created instance// just like the previous null check. 双重检查机制,如果创建了则直接返回result = instance;if (result == null) {// The instance is still not initialized so we can safely// (no other thread can enter this zone)// create an instance and make it our singleton instance. 如果仍然没有创建则我们可以在此处创建一个对象并赋值。instance = result = new ThreadSafeDoubleCheckLocking();}}}return result;}
}

静态内部类

在单例模式中,使用静态内部类实现是一种常见且线程安全的方式。通过静态内部类的特性,可以实现延迟加载和线程安全的单例对象。通过静态内部类实现的单例模式具有延迟加载、线程安全和高效的特点。在需要使用单例对象的时候才会进行实例化,而且能够保证多线程环境下的线程安全性。


/*** <p>The Initialize-on-demand-holder idiom is a secure way of creating a lazy initialized singleton* object in Java.</p>Initialize on demand holder习惯用法是在Java中创建延迟初始化的单例对象的一种安全方法。** <p>The technique is as lazy as possible and works in all known versions of Java. It takes* advantage of language guarantees about class initialization, and will therefore work correctly* in all Java-compliant compilers and virtual machines.</p>* 该技术尽可能懒惰,适用于所有已知版本的Java。它利用了关于类初始化的语言保证,因此将在所有符合Java的编译器和虚拟机中正确工作。* <p>The inner class is referenced no earlier (and therefore loaded no earlier by the class loader)* than the moment that getInstance() is called. Thus, this solution is thread-safe without* requiring special language constructs (i.e. volatile or synchronized).</p>**/
public final class InitializingOnDemandHolderIdiom {/*** Private constructor.*/private InitializingOnDemandHolderIdiom() {}/*** Singleton instance.** @return Singleton instance*/public static InitializingOnDemandHolderIdiom getInstance() {return HelperHolder.INSTANCE;}/*** Provides the lazy-loaded Singleton instance.*/private static class HelperHolder {private static final InitializingOnDemandHolderIdiom INSTANCE =new InitializingOnDemandHolderIdiom();}
}

枚举

使用枚举实现单例模式的优点包括:

  • 简洁明了:枚举实现单例模式非常简洁,只需声明一个枚举值,即可获得唯一实例。
  • 线程安全:枚举类型的实例是在类加载时初始化的,因此保证了线程安全性。
  • 序列化和反序列化安全:枚举类默认实现了Serializable接口,因此枚举单例在进行序列化和反序列化时,能够正确地保持实例的唯一性。
/*** <p>Enum based singleton implementation. Effective Java 2nd Edition (Joshua Bloch) p. 18</p>** <p>This implementation is thread safe, however adding any other method and its thread safety* is developers responsibility.</p>这种创建单例的方法是线程安全的,但是添加其他方法的线程安全问题需要开发者处理。*/
public enum EnumIvoryTower {INSTANCE;@Overridepublic String toString() {return getDeclaringClass().getCanonicalName() + "@" + hashCode();}
}

以上内容基于GPT创建和整理。

参考

  • 设计模式Java实现
  • 设计模式之美-王争

相关文章:

跟着GPT学设计模式之单例模式

单例设计模式&#xff08;Singleton Design Pattern&#xff09;一个类只允许创建一个对象&#xff08;或者实例&#xff09;&#xff0c;那这个类就是一个单例类&#xff0c;这种设计模式就叫作单例设计模式&#xff0c;简称单例模式。 单例有几种经典的实现方式&#xff0c;…...

【MySQL索引与优化篇】数据库调优策略

数据库调优策略 文章目录 数据库调优策略1. 数据库调优的措施1.1 调优目标1.2 如何定位调优问题1.3 调优的维度和步骤第1步&#xff1a;选择合适的DBMS第2步&#xff1a;优化表设计第3步&#xff1a;优化逻辑查询第4步&#xff1a;优化物理查询第5步&#xff1a;使用 Redis 或 …...

基于BP神经网络的风险等级预测,BP神经网络的详细原理,

目录 背影 BP神经网络的原理 BP神经网络的定义 BP神经网络的基本结构 BP神经网络的神经元 BP神经网络的激活函数, BP神经网络的传递函数 代码链接:基于BP神经网络的风险等级评价,基于BP神经网络的风险等级预测(代码完整,数据齐全)资源-CSDN文库 https://download.csdn.n…...

最新Ai智能创作系统源码V3.0,AI绘画系统/支持GPT联网提问/支持Prompt应用+搭建部署教程

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…...

项目资源不足,常见的5种处理方式

软件开发中&#xff0c;经常会遇到项目资源不足的情况&#xff0c;项目团队如果无法及时获得所需的人力、财力、物力等资源&#xff0c;往往会影响团队士气以及任务质量&#xff0c;造成无法按时完成任务&#xff0c;进而影响项目进度。 因此及时处理和应对资源不足的情况&…...

ER图设计神器,帮你省时省力,高效完成工作!

ER图&#xff08;Entity-Relationship Diagram&#xff09;工具用于设计数据库模型&#xff0c;通常用于表示数据实体、关系和属性之间的关系。以下是10个好用的ER图工具。 一、Lucidchart Lucidchart 是一款基于云的协作式图表设计工具&#xff0c;它允许用户创建、编辑和共享…...

Notepad++下载、使用

下载 https://notepad-plus-plus.org/downloads/ 安装 双击安装 选择安装路径 使用 在文件夹中搜索 文件类型可以根据需要设置 如 *.* 说明是所有文件类型&#xff1b; *.tar 说明是所有文件后缀是是tar的文件‘&#xff1b;...

基于若依的ruoyi-nbcio流程管理系统增加仿钉钉流程设计(一)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 仿钉钉的开源项目网上也不少&#xff0c;而且很多功能已经也比较完善了&#xff0c;但大部分都不是MIT协议…...

【知网检索征稿】第九届社会科学与经济发展国际学术会议 (ICSSED 2024)

第九届社会科学与经济发展国际学术会议 (ICSSED 2024) 2024 9th International Conference on Social Sciences and Economic Development 第九届社会科学与经济发展国际学术会议(ICSSED 2024)定于2024年3月22-24日在中国北京隆重举行。会议主要围绕社会科学与经济发展等研究…...

带你人工识别C#开源库BarcodeLib生成的一维码Code128

我们是做HIS系统开发的&#xff0c;前段时间发现某些处方的一维码出现无法识别的情况。看了一下一维码生成的逻辑&#xff0c;使用到了BarcodeLib库&#xff0c;经过反复确认&#xff0c;我们程序是没有问题的。后面不得不反编译看一下BarcodeLib生成一维码的逻辑。最后调整一维…...

软考 系统架构设计师系列知识点之系统架构评估(6)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之系统架构评估&#xff08;5&#xff09; 所属章节&#xff1a; 第8章. 系统质量属性与架构评估 第2节. 系统架构评估 8.2.1 系统架构评估中的重要概念 相关试题 3. 正确识别风险点、非风险点、敏感点和权衡点是进行软…...

指挥通信车360度3d虚拟互动展示系统的优势及特点

通信车是装有通信装备&#xff0c;用于保障通信联络的专用车辆&#xff0c;用于偏僻/特殊环境下的机动通信。并且机动通信局装备通常分为应急综合通信车、网络管理车、程控电话车、自适应跳频电台车、数字扩频接力车、散射通信车、卫星通信车、光缆引接车、线缆收放车和通信电源…...

根据Aurora发送时序,造Aurora 发送数据包

首先Aurora采用AXIS接口 由于后续需要进行AXIS接口 不同时钟域的数据位宽转换&#xff08;64bit和256bit之间的转换&#xff09;&#xff0c;因此分两次走。 第一种方法&#xff1a;采用AXIS数据位宽转换IP AXIS跨时钟域IP 第二种方法&#xff1a;逻辑完成 下面记录逻辑…...

vue实现一个账号在同一时间只有一个能登录的效果

目录 1.实现方法 2.实现示例 1.实现方法 要实现一个账号在同一时间只有一个能登录的效果&#xff0c;你可以使用以下步骤来实现&#xff1a; 在后端服务器端设置一个标志位&#xff0c;用于标记用户是否已登录。这个标志位可以存储在数据库中或者缓存在服务器内存中。当用户…...

react-hook-form。 useFieldArray Controller 必填,报错自动获取较多疑问记录

背景 动态多个数据Controller包裹时候&#xff0c;原生html标签input可以add时候自动获取焦点&#xff0c;聚焦到最近不符合要求的元素上面 matiral的TextField同样可以可是x-date-pickers/DatePicker不可以❌ 是什么原因呢&#xff0c;内部提供foucs&#xff1f;&#xff1f;属…...

最近收藏的各类好用API接口,含免费次数

IP应用场景- IPv4&#xff1a;IPv4应用场景是获取IP场景属性的在线调用接口&#xff0c;具备识别IP真人度&#xff0c;提升风控和反欺诈等业务能力。IP应用场景基于地理和网络特征的IP场景划分技术&#xff0c;将IP划分为含数据中心、交换中心、家庭宽带、CDN、云网络等共计18类…...

第01章 Linux下MySQL的安装与使用

第01章 Linux下MySQL的安装与使用 1. 安装前说明 1.1 查看是否安装过MySQL 如果你是用rpm安装, 检查一下RPM PACKAGE&#xff1a; rpm -qa | grep -i mysql # -i 忽略大小写检查mysql service&#xff1a; systemctl status mysqld.service1.2 MySQL的卸载 1. 关闭 mysql…...

kafka入门教程,介绍全面

1、官网下载最新版本的kafka&#xff0c;里面已经集成zookeeper。直接解压到D盘 2、配置文件修改&#xff0c;config目录下面的zookeeper.properties. 设置zookeeper数据目录 dataDirD:/kafka_2.12-3.6.0/tmp/zookeeper 3、修改kafka的配置文件server.properties. 主要修…...

万字解析设计模式之原型模式与建造者模式

一、原型模式 1.1概述 原型模式是一种创建型设计模式&#xff0c;其目的是使用已有对象作为原型来创建新的对象。原型模式的核心是克隆&#xff0c;即通过复制已有对象来创建新对象&#xff0c;而不是通过创建新对象的过程中独立地分配和初始化所有需要的资源。这种方式可以节…...

深度学习数据集大合集—疾病、植物、汽车等

最近又收集了一大批深度学习数据集&#xff0c;今天分享给大家&#xff01;废话不多说&#xff0c;直接上数据&#xff01; 1、招聘欺诈数据集 招聘欺诈数据集&#xff1a;共收集了 200,000 条数据&#xff0c;来自三个网站。 该数据集共收集了 200.000 条数据&#xff0c;分别…...

RK3399 Android7.1增加应用安装白名单机制

通过设置应用包名白名单的方式限制未授权的应用软件安装。 diff --git a/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java b/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java index af9a533..ca…...

C语言结构体的别名与创建结构体变量

这段代码是用C语言定义了一个链表节点的结构体&#xff0c;并通过typedef为相关类型创建了别名。下面分别解释Lnode和pNode&#xff1a; 1. Lnode Lnode是通过typedef为struct node定义的一个别名。struct node是一个结构体类型&#xff0c;表示一个链表节点。它的定义如下&a…...

历年中国科学技术大学计算机保研上机真题

2025中国科学技术大学计算机保研上机真题 2024中国科学技术大学计算机保研上机真题 2023中国科学技术大学计算机保研上机真题 在线测评链接&#xff1a;https://pgcode.cn/school?classification1 拆分数字 题目描述 给定一个数字&#xff0c;拆分成若干个数字之和&#xff…...

2025年渗透测试面试题总结-匿名[校招]安全服务工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 匿名[校招]安全服务工程师 一面问题与完整回答 1. 学校、专业、成绩与排名 2. 学习安全时长 3. 当前学习…...

AI炼丹日志-25 - OpenAI 开源的编码助手 Codex 上手指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; Java篇&#xff1a; MyBatis 更新完毕目前开始更新 Spring&#xff0c;一起深入浅出&#xff01; 大数据篇 300&#xff1a; Hadoop&…...

Nginx--手写脚本压缩和切分日志(也适用于docker)

原文网址&#xff1a;Nginx--手写脚本压缩和切分日志&#xff08;也适用于docker&#xff09;_IT利刃出鞘的博客-CSDN博客 简介 本文介绍nginx如何手写脚本压缩和切分日志。 1.创建切分日志的脚本 创建脚本文件&#xff1a;/work/tmp/nginx-log_sh&#xff08;后边要用run-…...

Mobaxterm解锁Docker

Mobaxterm是一款功能强大的终端模拟器和SSH客户端&#xff0c;它支持Windows、Linux和Mac操作系统&#xff0c;对于使用Docker的开发者和运维人员来说&#xff0c;Mobaxterm是一个非常有用的工具。本文将深入解析Mobaxterm&#xff0c;并分享一些使用Docker时的高效技巧。 Mob…...

Oracle中EXISTS NOT EXISTS的使用

目录 1.IN与EXISTS EXISTS用法总结 2.NOT IN与NOT EXISTS 3.not in 中 null的用法 4.EXISTS和IN的区别 (面试常问) 1.IN与EXISTS 示例&#xff1a;在 DEPT 表中找出在 EMP 表中存在的部门编号&#xff1b; 方法一&#xff1a;使用in select DEPTNO from DEPT where D…...

Axure设计案例——科技感渐变线性图

想让数据变化趋势展示告别枯燥乏味&#xff0c;成为吸引观众目光的亮点吗&#xff1f;快来看看这个Axure设计的科技感渐变线性图案例&#xff01;科技感设计风格凭借炫酷的渐变色彩打破传统线性图的单调&#xff0c;营造出一种令人过目难忘的视觉体验。每一条线条都仿佛是流动的…...

【第4章 图像与视频】4.5 操作图像的像素

文章目录 前言示例-获取和修改图像数据图像数据的遍历方式图像滤镜负片滤镜黑白滤镜浮雕滤镜filter滤镜属性 前言 getImageData() 与 putImageData() 这两个方法分别用来获取图像的像素信息&#xff0c;以及向图像中插入像素。与此同时&#xff0c;如果有需要&#xff0c;也可…...