java八股文补充

news2024/12/26 11:07:56

1、JAVA BIO、NIO、AIO的区别

BIO (Blocking I/O):同步阻塞I/O模式。当有其他线程进行数据读写时阻塞等待。当用户线程发出IO请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待,用户线程就会处于阻塞状态交出CPU。当数据就绪之后,操作系统就会将数据从主内存拷贝到线程工作内存,并返回结果给用户线程,才解除阻塞状态。(类似重量级锁)

NIO(nonblocking I/O):同步非阻塞I/O。当用户线程发起一个read操作后,并不需要等待,而是马上就得到了一个结果。如果结果是一个error时(数据未准备就绪),它就知道数据还没有准备好,于是它可以再次发送read操作。一旦内核中的数据准备好了,并且又再次收到了用户线程的请求,那么它马上就将数据拷贝到了用户线程,然后返回。所以事实上,在非阻塞IO模型中,用户线程需要不断地询问主内存数据是否就绪,也就说非阻塞IO不会交出CPU,而会一直占用CPU。(类似CAS)

AIO(Asynchronous I/O) 异步非阻塞I/O。当用户线程发起了个I/O操作后立即返回,执行该线程的其他任务。当I/O操作真正完成之后,会通知用户线程,用户线程只需要处理读取的数据即可,不需要实际的I/O操作,真正的I/O读写已经由内核完成了。

2、JAVA NIO

NIO主要有三大核心部分:Channel、Buffer、Selector。
传统IO基于字节流和字符流,而NIO基于Channel和Buffer进行操作,数据总是从通道读取到缓冲区,或者从缓冲区写入到通道中。Selector用于监听多个通道的事件(连接打开,数据到达等)。
在这里插入图片描述
NIO的buffer(缓冲区):普通的I/O面向流意味着每次从流中读取一个或者多个字节,直到读取完所有字节,没有缓存在任何地方。NIO将数据读取到一个缓冲区,需要时可以在缓冲区中前后移动,这增加了处理的灵活性。但是需要检查缓冲区中是否包含需要的数据,还要保证读取更多数据时不会覆盖尚未处理的数据。
在这里插入图片描述

上述图描述了客户端向服务器端发送数据,然后被服务器端接收的过程。通道之间可以进行数据的交换,而客户端和服务器端发送和接收数据都必须经过Buffer。

channel:stream流是单向的,而Channel是双向的,既可以用来读操作,也可以进行写操作。分别有FileChannel、DatagramChannel、SocketChannel、ServerSocketChannel,对应文件I/O、UDP和TCP

selector:Selector能够检测多个注册的通道上是否有事件发生,如果有事件发生,便获取事件然后针对每个事件进行相应的响应处理。这样一来,只是用一个单线程就可以管理多个通道,也就是管理多个连接,避免了为每一个连接都创建一个线程增加开销。

3、以下几种情况不会出发类的初始化

  1. 通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化。
  2. 定义对象数组,不会触发该类的初始化。
  3. 常量在编译期间会存入调用类的常量池中,本质上没有直接引用定义常量的类,不会触发定义常量所在的类。
  4. 通过类名获取Class对象,不会触发类的初始化。
  5. 通过Class.forName加载指定类时,如果指定参数initialize为false时,也不会触发类初始化,其实这个参数是告诉虚拟机,是否要对类进行初始化。
  6. 通过ClassLoader默认的loadClass方法,也不会触发初始化动作。

4、线程池的种类

Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService
在这里插入图片描述
Executors可以创建四种线程池,分别是:
Executors.newCachedThreadPool:如果有可用的线程调用execute时会重用,没有可用的将创建一个新的线程加入池中。会终止并移除60秒未被使用的线程。
Executors.newFixedThreadPool:创建固定数量线程的线程池,如果所有线程都不可用,新的任务将在队列中等待可用线程。线程没有被显示关闭则一直在线程池中。
Executors.newScheduledThreadPool:创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。

ScheduledExecutorService scheduledThreadPool= Executors.newScheduledThreadPool(3); 
scheduledThreadPool.schedule(new Runnable(){ 
		@Override public void run() { 
		System.out.println("延迟三秒"); 
		} 
}, 3, TimeUnit.SECONDS); 
scheduledThreadPool.scheduleAtFixedRate(newRunnable(){ 
		@Override public void run() { 
		System.out.println("延迟1秒后每三秒执行一次"); 
		} 
},1,3,TimeUnit.SECONDS);

Executors.newSingleThreadExecutor:线程池只有一个线程,可以在线程死后(或发生异常时)重新启动一个线程来替代原来的线程继续执行下去!

使用线程池的好处:
线程复用,控制并发度,线程同一管理。

5、如何进行锁优化

减少锁持有时间:只用在有线程安全要求的程序上加锁
减小锁粒度:将大对象(这个对象可能会被很多线程访问),拆成小对象,大大增加并行度,降低锁竞争。降低了锁的竞争,偏向锁,轻量级锁成功率才会提高。最最典型的减小锁粒度的案例就是ConcurrentHashMap。
锁分离:最常见的锁分离就是读写锁ReadWriteLock,根据功能进行分离成读锁和写锁,这样读读不互斥,读写互斥,写写互斥,即保证了线程安全,又提高了性能。
锁粗化:通常情况下,为了保证多线程间的有效并发,会要求每个线程持有锁的时间尽量短。但是,凡事都有一个度,如果对同一个锁不停的进行请求、同步和释放,其本身也会消耗系统宝贵的资源,反而不利于性能的优化,此时粗化反而会提升性能。
锁消除 :锁消除是在编译器级别的事情。在即时编译器时,如果发现不可能被共享的对象,则可以消除这些对象的锁操作,多数是因为程序员编码不规范引起。

6、java中的阻塞队列

阻塞队列的原理

  1. 当队列中没有数据的情况下,消费者端的所有线程都会被自动阻塞(挂起),直到有数据放入队列。
  2. 当队列中填满数据的情况下,生产者端的所有线程都会被自动阻塞(挂起),直到队列中有空的位置,线程被自动唤醒。

阻塞队列的主要方法
在这里插入图片描述
在这里插入图片描述
ArrayBlockingQueue(公平、非公平):用数组实现的有界阻塞队列。按照先进先出(FIFO)的原则对元素进行排序。默认情况下不保证访问者公平的访问队列。

LinkedBlockingQueue(两个独立锁提高并发):基于链表的阻塞队列,先进先出(FIFO),对于生产者端和消费者端分别采用了独立的锁来控制数据同步,生产者和消费者可以并发,从而提升性能。

PriorityBlockingQueue(compareTo排序实现优先):可以自定义排序,需要注意的是不能保证同优先级元素的顺序。

DelayQueue(缓存失效、定时任务 ):队列使用PriorityQueue来实现。队列中的元素必须实现Delayed接口,在创建元素时可以指定时间,只有在延迟期满时才能从队列中提取元素。

SynchronousQueue(不存储数据、可用于传递数据):一个不存储元素的阻塞队列。每一个put操作必须等待一个take操作,否则不能继续添加元素。非常适合于传递性场景,吞吐量高于LinkedBlockingQueueArrayBlockingQueue

7、进程的调度算法

先来先服务调度算法(FCFS):作业调度按照线程的启动顺序进行分配资源。公平。
短作业优先算法:从就绪队列中选择估计运行时间最短的进行分配资源。
高优先权优先调度算法:1.抢占式优先权算法:执行期间只要出现优先权更高的进程,就把处理机重新分配给高优先权的进程 2.非抢占式优先权算法:等当前进程执行完后,选择优先权高的进程分配资源 3:高响应比优先调度算法,通过比较响应比进行进程的调度。
时间片轮换算法:将就绪的进程按照给定的时间片依次运行,当前进程执行完时间片后就排到就绪队列的队尾。
多级反馈队列调度算法:设置多个就绪队列,每个队列的时间片大小不同(依次增大),当上层队列中的时间片用完时,进程进入下一层就绪队列中进行等待,上层队列中空闲时后再调度下层就绪队列中的进程。

8、java中常见的运行时异常和非运行时异常

运行时异常:在编译期不会发现,通常是逻辑错误导致的异常。如NullPointerException,ClassCastException

非运行时异常:在编译阶段,java编译器就会强制去捕获此类异常,否则编译不通过。例如:IOException、SQLException

9、Spring的特点

轻量级:体积小,开销小。
控制反转:对象的创建和使用通过Spring框架来完成,降低了代码的耦合性。
面向切面:使用动态代理的技术,将应用业务逻辑和系统服务分开。
容器:Spring是一种容器,包含并管理对象的配置和生命周期。
框架:提供了很多开箱即用的功能(事务管理,数据库连接等),只把逻辑的开发留给开发者。

10、spring依赖注入的四种方式

构造器注入:

/*带参数,方便利用构造器进行注入*/
public CatDaoImpl(String message){
this. message = message;
}
<bean id="CatDaoImpl" class="com.CatDaoImpl">
<constructor-arg value=" message "></constructor-arg>
</bean>

setter方法注入:

public class Id {
private int id;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
}
<bean id="id" class="com.id "> <property name="id" value="123"></property> </bean>

静态工厂注入:

public class DaoFactory { //静态工厂
	public static final FactoryDao getStaticFactoryDaoImpl(){
		return new StaticFacotryDaoImpl();
	}
}
public class SpringAction {
	private FactoryDao staticFactoryDao; //注入对象
	//注入对象的set方法
	public void setStaticFactoryDao(FactoryDao staticFactoryDao) {
		this.staticFactoryDao = staticFactoryDao;
	}
}
//factory-method="getStaticFactoryDaoImpl"指定调用哪个工厂方法
<bean name="springAction" class=" SpringAction" >
<!--使用静态工厂的方法注入对象,对应下面的配置文件-->
<property name="staticFactoryDao" ref="staticFactoryDao"></property>
</bean>
<!--此处获取对象的方式是从工厂类中获取静态方法-->
<bean name="staticFactoryDao" class="DaoFactory"
factory-method="getStaticFactoryDaoImpl"></bean>

通过实例工厂注入:

public class DaoFactory { //实例工厂
	public FactoryDao getFactoryDaoImpl(){
		return new FactoryDaoImpl();
	}
}
public class SpringAction {
	private FactoryDao factoryDao; //注入对象
	public void setFactoryDao(FactoryDao factoryDao) {
		this.factoryDao = factoryDao;
	}
}

<bean name="springAction" class="SpringAction">
<!--使用实例工厂的方法注入对象,对应下面的配置文件-->
<property name="factoryDao" ref="factoryDao"></property>
</bean>
<!--此处获取对象的方式是从工厂类中获取实例方法-->
<bean name="daoFactory" class="com.DaoFactory"></bean>
<bean name="factoryDao" factory-bean="daoFactory"
factory-method="getFactoryDaoImpl"></bean>

11、网络的OSI七层架构

物理层:等一了物理接口标准以及电气特性。数据为比特

数据链路层:将物理层接收的数据进行MAC地址封装/解封装。工作设备为交换机,数据为

网络层:将接收到的数据进行IP地址的封装和解封装,以及进行路由选择。工作设备为路由器,数据为数据包

传输层:定义了一些传输协议(TCP/UDP)和端口号。将下层接收到的数据进行分段传输。数据为

会话层:通过传输层建立数据传输的通路,在设备之间发起会话或者接收会话请求。

表示层:主要是进行对接收的数据进行解释、加密与解密、压缩与解压缩等,(也就是把计算机能够识别的东西转换成人能够能识别的东西(如图片、声音等))

应用层:主要是一些终端的应用。

12、TCP/IP参考模型

TCP/IP由四个层次组成:网络接口层、网络层、传输层、应用层。
在这里插入图片描述
网络接口层:指出主机必须使用某种协议与网络相连。
网络层:分组转发,这些分组可以通过不同的网络,到达的顺序和发送的顺序也可能不同,高层如果需要顺序收发,那么就必须自行处理对分组的排序。
传输层:在这一层定义了两个端到端的协议:传输控制协议(TCP,Transmission Control Protocol)和用户数据报协议(UDP,User Datagram Protocol)。
应用层:文件传输协议(FTP)、电子邮件传输协议(SMTP)、域名服务(DNS)、和超文本传送协议(HTTP)等。

13、三次握手和四次挥手

TCP建立连接需要三次握手:
首先服务器端创建一个传输控制块,进入listen状态。

第一次握手:
然后客户端创建一个传输控制块,开始发送一个连接请求报文:
SYN=1,seq=x,进入syn_sent状态

第二次握手:
服务器端收到客户端的请求之后,同意与它连接,并发送一个同意请求连接的报文:
SYN=1,ACK=1,seq=y,ack=x+1(客户端的序列号+1),进入syn_recieve状态

第三次握手:
客户端收到服务器的确认连接后,再次发送一个确认收到对方确认的报文:
SYN=1,ACK=1,seq=x+1(等于对方的确认号),ack=y+1,进入连接状态

服务器端收到客户端的确认之后,进入连接状态。

TCP断开连接的四次挥手:(由于TCP的连接是全双工的,所以关闭时需要两个方向上都单独进行关闭)
第一次挥手:
首先客户端这边主动发送一个请求断开连接的报文:
FIN=1,seq=x;进入终止等待1.

第二次挥手:
服务器端收到断开请求后,发送一个同意断开的报文:
ACK=1,ack=x+1,seq=y;进入关闭等待1

第三次挥手:
服务器准备好断开后,发送一个请求断开的报文:
FIN=1,seq=z;进入最后等待阶段。

第四次挥手:
客户端收到服务器端的断开请求后,发送一个同意断开的报文:
ACK=1,ack=z+1,seq=h;客户端正式进入终止等待2。

服务器接收到客户端的确认之后,立即进入close状态。
客户端等待2MSL(报文最大生命)后,也进入close状态。(原因:为了防止最后一个ACK报文服务器没有收到,它要继续给服务器端发送ACK报文。)

14、HTTP原理

HTTP是一个无状态协议,意味着客户端(web浏览器)服务器之间不需要建立持久的连接。当客户端发起请求,然后服务器端返回应答,连接就被关闭了,服务器端不保留连接有关的信息。所有HTTP连接都被构造成一套请求和应答。(默认80端口)

传输的流程
1.地址解析:根据域名到DNS服务器上解析出主机的IP地址

2.封装HTTP数据包:把域名解析到的数据和客户端自己的信息封装成一个HTTP请求包。

3.封装成TCP包并建立连接(三次握手)

4.建立连接后,浏览器发送一个请求给服务器

5.服务器接收到请求之后,基于相应的响应信息。

6.服务器关闭TCP连接:一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了这行代码Connection:keep-alive,TCP连接在发送后将仍然保持打开状态,节省了网络带宽。

15、HTTPS

HTTPS,是以安全为目标的HTTP通道,简单讲是HTTP+SSL层。(默认端口号443)

HTTPS的整体过程分为证书验证和数据传输阶段,具体的交互过程如下:
在这里插入图片描述
① 证书验证阶段
1.浏览器发起 HTTPS 请求
2.服务端返回 包含公钥HTTPS 证书。客户端验证证书是否合法,如果不合法则提示告警

② 数据传输阶段
1.当证书验证合法后,在本地生成随机数
2.通过公钥加密随机数,并把加密后的随机数传输到服务端
3.服务端通过私钥对随机数进行解密
4.服务端通过客户端传入的随机数构造对称加密算法,之后双方通过该随机数秘钥进行加密通话。

对称秘钥加密:双方通过同一把秘钥进行数据的加密和解密。
非对称秘钥加密:一方通过公钥进行加密,一方通过另一把私钥进行解密。

16、关系型数据库和非关系型数据库的区别

在这里插入图片描述

1、数据存储方式不同

  • 关系型数据库天然就是表格式的,数据表可以彼此关联存储,也很容易提取数据。
  • 而非关系型数据库是以key-value的形式存储的

2、事务的支持不同

  • 关系型数据库汇总有事务的概念
  • 非关系型数据库中没有事务,它的每一个数据集都是原子级别的

3、扩展方式不同

  • 关系型数据库容易纵向扩展,但是想要横向扩展就必须改变表结构
  • 非关系型数据库天然是分布式的,很灵活,容易横向扩展

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/836558.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux下多python版本共存

python下载官网 https://www.python.org/downloads/ python支持多版本共存&#xff0c;是大版本共存&#xff0c;小版本不共存。 python3.6 和 3.7 共存python3.6.6和python3.6.8 不共存 1.下载特定版本的python 进入官网后点击Downloads–>All releases点击‘Gzipped s…

在职读研想要成功上岸,社科院杜兰大学金融管理硕士机不可失

近年来&#xff0c;中国考研报名人数节节攀升&#xff0c;2023年考研报名人数达到了474万。在如此庞大的考生群体中&#xff0c;成功被录取的人数却不足两成&#xff0c;这一数字引起了社会各界广泛的热议和关注。招生规模如此浩大&#xff0c;录取率却如此之低。其实考研录取率…

【2023年电赛国一必备】C题报告模板--可直接使用

任务 图1 任务内容 要求 图2 基本要求内容 图3 发挥部分内容 说明 图4 说明内容 评分标准 图5 评分内容 正文 &#xff08;部分&#xff09; 摘要 本实验基于TI公司的TM4C123GH6PM主控&#xff0c;结合OPA2337芯片和其他硬件模块&#xff0c;设计并制作了一种单相逆变器…

如何快速完成 App 安全评估报告【最快当天完事】

文章目录 1. App下架展示2. 检查App是否存在问题3. 注册《安全评估》 信息4. 人工快速干预&#xff0c;加快审核步骤5. 面审阶段6. 后续 1. App下架展示 在华为应用市场上架的App突然间被下架&#xff0c;把我搞得猝不及防&#xff0c;原因如下&#xff1a; 是因为我们缺少 《…

提升项目管理效率的优秀软件推荐

Zoho Projects项目管理软件拥有随需而配的强大项目功能&#xff0c;帮助项目经理实现整体项目把控。系统以“动态管理、实时共享”的先进理论实现项目进度、成本、资源、绩效、风险等的有效跟进&#xff0c;解决项目管理中因信息滞后导致的项目失败问题&#xff0c;提升企业项目…

2.虚拟机开启kali_linux

首先你应该搞一个虚拟机&#xff0c;搞虚拟机可以看一下这个 附录三 虚拟机的使用_Suyuoa的博客-CSDN博客 然后你需要搞一个 kali linux的镜像 Get Kali | Kali Linux 镜像下载好之后解压&#xff0c;你会得到一个文件夹包含下面这些文件 之后打开VMware&#xff0c;点击打开虚…

Java SpringBoot集成Activiti7工作流

Activiti7 Java SpringBoot集成Activiti7工作流介绍项目集成引入依赖YML配置文件配置类 启动项目生成表结构Activiti的数据库支持 Activiti数据表介绍项目Demo地址&#xff1a; Java SpringBoot集成Activiti7工作流 本文项目Demo地址附在文章后方 官网主页&#xff1a;http://a…

Java 离线导包

Java 离线导包 1、问题2、解决方法 1、问题 import org.apache.commons.lang3.StringUtils; 报红色 2、解决方法 下载离线包或者在meven的repository中找到下载好的包&#xff0c;如commons-lang3-3.12.0.jar File->Project Structure->Libraries-> Java 选择离线…

OpenCV图像处理技巧之空间滤波

1. 引言 再次问好&#xff0c;图像处理爱好者们&#xff01;&#x1f31f; 在前面的章节中&#xff0c;我们学习了图像处理的基础知识&#xff0c;并展现了图像增强的魅力。在这一节中&#xff0c;我们将更深入地研究空间滤波技术。 闲话少说&#xff0c;我们直接开始吧&#…

C++20 协程(coroutine)入门

文章目录 C20 协程&#xff08;coroutine&#xff09;入门什么是协程无栈协程和有栈协程有栈协程的例子例 1例 2 对称协程与非对称协程无栈协程的模型无栈协程的调度器朴素的单线程调度器让协程学会等待Python 中的异步函数可等待对象M:N 调度器——C# 中的异步函数 小结 C20 中…

LabVIEW深度相机与三维定位实战(下)

‍‍&#x1f3e1;博客主页&#xff1a; virobotics的CSDN博客&#xff1a;LabVIEW深度学习、人工智能博主 &#x1f384;所属专栏&#xff1a;『LabVIEW深度学习实战』 &#x1f37b;上期文章&#xff1a;『LabVIEW深度相机与三维定位实战&#xff08;上&#xff09;』 &#…

《Python入门到精通》循环语句 while循环,for循环

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;小白零基础《Python入门到精通》 循环语句 1、语法格式1.1、while1.2、死循环1.3、简写形式 2、continue 跳过循环…

synchronized总结

目录 一、synchronized的特性 1.1 原子性 1.2 可见性 1.3 有序性 1.4 可重入性 二、synchronized的使用 2.1 修饰普通方法 2.2 修饰静态方法 2.3 修饰代码块 三、synchronized的锁机制 3.1 偏向锁 3.2 轻量级锁 3.3 重量级锁 一、synchronized的特性 1.1 原子性 原子性是指一…

【逗老师的PMP学习笔记】3、项目经理的角色和能力

个人感觉这一篇属于打鸡血篇&#xff0c;与实战关联较弱。主要各位要思考一下&#xff0c;做好一个项目经理&#xff0c;在哪些overall的领域和能力上要让自己牛逼 一、开篇一张图 总结一句话&#xff0c;项目经理更像是一直大型交响乐团的**指挥** &#xff08;除了正向的&a…

Streamlit应用中构建多页面(三):两种方案

文章目录 1 前言2 第一种方案&#xff1a;使用Session State实现多页面交互2.1 Session State简介2.2 多页面应用的基本结构2.3 实现多页面交互的代码示例2.4 Session State机制的优缺点 3 第二种方案&#xff1a;Streamlit内置多页面方案&#xff08;更为推荐&#xff09;3.1 …

DoIP学习笔记系列:(三)用CAPL脚本过“安全认证”,$27服务实现

文章目录 1. 如何调用接口通过安全认证?如何新建CAPL工程,在此不再赘述,本章主要分享一下如何在CAPL中调用DoIP接口、diag接口进行DoIP和诊断的测试。 注意:CANoe工具本身的使用没什么难的,所谓会者不难难者不会,各位小伙伴有疑问要多问,多交流,往往难事都只是一层窗户…

生鲜蔬果小程序的完整教程

随着互联网的发展&#xff0c;线上商城成为了人们购物的重要渠道。其中&#xff0c;小程序商城在近年来的发展中&#xff0c;备受关注和青睐。本文将介绍如何使用乔拓云网后台搭建生鲜果蔬配送小程序&#xff0c;并快速上线。 首先&#xff0c;登录乔拓云网后台&#xff0c;进入…

(具体解决方案)训练GAN深度学习的时候出现生成器loss一直上升但判别器loss趋于0

今天小陶在训练CGAN的时候出现了绷不住的情况&#xff0c;那就是G_loss&#xff08;生成器的loss值&#xff09;一路狂飙&#xff0c;一直上升到了6才逐渐平稳。而D_loss&#xff08;判别器的loss值&#xff09;却越来越小&#xff0c;具体的情况就看下面的图片吧。其实这在GAN…

【设计模式】——工厂模式

什么是工厂模式&#xff1f; Java的工厂模式是一种创建型设计模式&#xff0c;它提供了一种创建对象的最佳方式。在工厂模式中&#xff0c;我们在创建对象时不会对客户端暴露创建逻辑&#xff0c;而是通过使用一个共同的接口来指向新创建的对象。这种类型的设计模式属于创建型…

替换开源LDAP,西井科技用宁盾目录统一身份,为业务敏捷提供支撑

客户介绍 上海西井科技股份有限公司成立于2015年&#xff0c;是一家深耕于大物流领域的人工智能公司&#xff0c;旗下无人驾驶卡车品牌Q-Truck开创了全球全时无人驾驶新能源商用车的先河&#xff0c;迄今为止已为全球16个国家和地区&#xff0c;120余家客户打造智能化升级体验…