`
sunlujing
  • 浏览: 180598 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

ClassLoader 深入解析

    博客分类:
  • j2se
阅读更多

 

 

本文是根据是在《北京圣思园深入JAVA虚拟机系列视频》的基础上自己整理而来,内容范围没有超过其系列所述,在此给予说明。

在进入ClassLoader的分析之前我们先看一个JAVA程序例子。

 

class Singleton {

         /* case 1 */

         private static Singleton singleton = new Singleton();

         public static int counter1;

         public static int counter2 = 0;

 

         /**

          * case 2

* public static int counter1 = 0;

* public static int counter2 = 0;

          * private static Singleton singleton = new Singleton();

          */

         private Singleton() {

                   counter1++;

                   counter2++;

         }

 

         public static Singleton getInstance() {

                   return singleton;

         }

}

 

public class MyTest {

         public static void main(String[] args) {

                   Singleton singleton = Singleton.getInstance();

                   System.out.println("counter1 = " + singleton.counter1);

                   System.out.println("counter2 = " + singleton.counter2);

         }

}

/**

 * result in case 1:

 * counter1 = 1

 * counter2 = 0

 * result in case 2:

 * counter1 = 1

 * counter2 = 1

 */


 

上面的代码在case1 case2 条件下运行结果却不一样,仅仅由于private static Singleton singleton = new Singleton();位置不同,要想了解其中的原因需要从类的使用时JVM完成的动作说起,在一个类被JVM使用时大致经历如下三步(加载 链接(验证--准备--解析) 初始化)


 

那么一个类被JVM使用时,必须预先经历如上图所述的加载过程。那么什么样的条件才会触发上述过程的执行呢?JAVA程序使用类分为主动使用和被动使用,在JVM的实现规范中要求,所有类的“主动使用“虚拟机才执行上述过程初始化相应的类,那么问题就归结为“主动使用”的意义。

  1. 创建类的实例。Object A = new ClassA();

2.  访问某个类或接口的静态变量或对静态变量赋值。如Class A{static a} 访问A.a时。需要 指出的是访问类的static final int x = 0(编译时常量)并不被认为是类的主动使用,同样 的假如有条件 Class A extends B;B{static a}如果使用A.a时只会初始化类B,这种情况被认 为是对父类的主动使用。

3. 调用类的静态方法

4.使用反射机制(Class.ForName(xxx),ClassLoader.load(并不会初始化类)

5. 初始化一个类的子类时,父类也被主动使用

6.   启动类(java TestMain

 

下面文章将针对上述过程给出比较详细的说明。

加载过程

总的来说类的加载是JVM使用类加载器(如系统类加载器、扩展加载器、根加载器)在特定的加载路径里寻找class文件,并将class文件中的二进制数据读入到内存中,其中class的数据结构被放置在运行时数据区的方法区类,并且在堆区里创建该类的Class对象,用来封装类的数据结构信息。其中类加载类的方式有:文件系统加载、网络加载、zip jar 归档文件加载、数据库中提取、动态编译的源文件加载。

 

类加载的最终产品是位于堆区中的Class对象,其封装了类在方法区内数据结构,并且向Java程序员提供了访问方法区内数据结构的接口,需要指出的是,类的加载并不都是主动使用时才加载,加载器可以实现为有预加载功能,如使用一定的算法预测类的使用。在上面的叙述中我们提到过JVM使用类加载器对class文件进行加载(本文后面部分将着重描述类的加载机制)。


 

连接过程

类加载后,就是连接阶段了,连接就是将已经读入到内存的类的二进制数据合并到虚拟机的运行环境中去。连接的第一个阶段是类的验证,验证的内容如下:

1.类文件结构的检查,确保类的文件遵循java类文件的固定格式。

2. 语义检查:确保类本身符合java语言的语法规定,比如验证final类型没有子 类,final方法没有被从写,private没有被重写。

3.  字节码验证:确定字节码流可以被java虚拟机安全的执行。

4.二进制兼容验证:确保相互应用的类之间协调一致。

做完验证之后就是类的准备阶段,完成的工作为类的静态变量分配内存并设置为初始值。如有类

Sample{

Static int a = 1;

Static long b;

}

系统会为 a 分配4个字节,并设置初始值为 0,为b分配8个字节并设置初始值为 0.

 

做完类的准备工作之后就是类的解析,主要工作就是把类中的二进制中的符号引用替换为直接引用。我们举个例子 void show{  objectA.print()};objectA.print() 就是对ClassA的一个符号引用,经过解析之后该处的代码会被一个指向ClassA中方法区print方法的指针。

初始化过程

下面是类的初始化过程,初始化的主要步骤为:检查该类是否已经被加载和连接;如果该类有父类,且没有初始化,对父类进行加载 连接 初始化;假如类中存在初始化语句,依次执行初始化语句。而静态变量的声明以及静态代码块都被看作是类的初始化语句,java虚拟机会按照初始化语句在类文件中的顺序依次来执行他们。如 static int a =1,static{ a = 3}这样的语句都会被JVM顺序执行。

         前面提到,当JVM初始化一个类时要求他的父类已经被初始化,这样的机制并不适用于接口,初始化一个类时,它实现的接口并不需要被初始化,初始化一个接口时,其父接口也不需要被初始化,只有当程序首次使用接口中的静态变量时,才会导致接口的初始化。

         通过上面的论述,我们大致对类的使用有了一个初步的了解,接下来我们将分析本文开始时提出的那个程序的运行结果

case 1 中,在MyTest那种使用 Singleton singleton = Singleton.getInstance();这样的语句为类的主动使用这会触发Singleton类的加载 连接 初始化。

  private static Singleton singleton = new Singleton();A

       public static int counter1;B

       public static int counter2 = 0;C

在加载完后的连接阶段的准备期,会为singleton分配内存,设定默认值为nullcounter1默认值为 0counter2 默认值为 0. 进入初始化阶段,第一步为singleton赋值 会调用Singleton的构造方法,此时执行counter1++counter2++ counter1 = 1,counter2 = 1;第二步为counter1赋值,由于没有赋值语句counter1 仍为1;第三步为 counter2赋值,counter2 被赋值为 0,所以结果是counter1 =1

Counter2 =0

         case2 使用如下语句

       public static int counter1;A

       public static int counter2 = 0;B

       private static Singleton singleton = new Singleton();C

连接准备阶段结束后counter1 = 0,counter2 = 0,singleton = null;初始化时 第一步A语句不用初始化 counter1 =0;第二部B语句初始化为0counter2 =0;第三步 调用构造函数 counter1++counter2++ counter1 = 1,counter2 = 1;所以case2的结果为 counter1 =1 counter2 = 1

在下面的部分,我将给大家深入的介绍一下JVM的类加载器。


 

类加载器分析

         在上面的例子中我们看到一个类的主动使用会经历加载、链接、初始化的过程,类的加载需要使用JVM的类加载器,JVM的类加载器使用父亲委托机制。我们首先看看JVM的类加载器树形结构:

          BootStrap(根类加载器)

              ||

          Extend(扩展类加载器)

              ||

    System(系统类或应用类加载器)

              ||

  用户自定义类加载器


从上面的结构可以看出,JVM的类加载器一共有四大类,其中根类加载器、扩展类加载器、系统类加载器(应用类加载器)为JVM自带的类加载器。

1.根类加载器。负责加载虚拟机的核心类库,如java.lang.*等。根类加载器从系统 属性sun.boot.class.path 所指定的目录中加载类库。根类加载器的实现依赖于底层 操作系统,属于jvm实现的一部分,使用c++语言编写。它并没有ClassLoader类, 也没有父加载器。使用如stringObject.getClass().getClassLoader()将返null

  2. 扩展类加载器(Ext)。从图中可以看出它的父加载器是根加载器。它 java.ext.dirs系统属性所指定的目录中加载类库,或者从jdk的安装目录 jre\lib\ext子目录下加载类库,如果你把用户创建的jar放在这个目录下会被扩展类 加载器加载。扩展类加载器使用纯java实现,继承了ClassLoader

3.    系统类加载器,也叫应用类加载器(APP),它的父加载器是Ext加载器。它从 环境 变量里(安装JDK时设立的classpath)或从系统属性java.class.path加载 类,它是 用户自定义的类加载器的默认父加载器,采用纯java实现,继承 ClassLoader

4.   用户自定义加载器。系统类加载器的子类,必须要继承自ClassLoader之类,并 且重 findClass方法。

假设我们自定义ClassLoader loadA,并且使用loadA.load(Class),所谓的父亲委托机制就是loadA 委托父加载器(App)加载ClassApp委托ExtExt委托BootStrap,如果BootStrap不能加载,则让Ext加载,逐级下发,如果直到loadA还不能加载Class这抛出ClassNotFindException。委托机制是SUN公司基于安全性考虑的,这样可以保证Object这样的重要类只能有JVM加载。我们定义若一个类加载器能够成功加载类Class,我们则称这个加载器为该类的定义加载器,其下的子加载器为初始化加载器。如在上述的类之中,假设App类加载器加载了类Class App为定义加载器,APPLoadA为初始化加载器。

需要指出的是加载器之间的父子关系并不是指类之间的继承关系,而是指加载器之间的包装关系。一对父子可能是同一个类加载器的实例,也可能不是。例如我们自定义类加载器MyClassLoaderLoadA = new MyClassLoader(); LoadB = new MyClassLoader(loadA), 我们称loadB包装了loadALoadAloadB的父加载器。

运行时包决定了protecetd类和protected成员是否能够访问。我们知道所有的protected的成员需要同一个包下的类才能访问。如果我们定义java.lang.Spy类,我们是否就能访问java.lang.*下的核心protected资源呢?运行时包包括,包名相同,类加载器相同,所有java.lang.Spy java.lang.* 不在相同的运行时包,答案是否定的。

 

下面我们以视频中一个详细的例子来讲述用户自定义加载器的实现。首先给出例子中类加载器的树形关:   

 

           BootStrap(根类加载器)

              ||               \\

        ||          LoaderC -----> d:app/otherlib           

          Extend(扩展类加载器)

              ||

    System(系统类或应用类加载器)

              ||

  LoaderB    ------> d:app/serverlib

              ||              

    LoaderA    ------> d:app/clientlib 


 

在例子中我们定义三个类加载器,在重写的findClass方法中设定好加载路径。JDK API给出一个自定义ClassLoad的方法:

 class MyClassLoader extends ClassLoader {

         public Class findClass(String name) {

             byte[] b = loadClassData(name);

             return defineClass(name, b, 0, b.length);

         }

         private byte[] loadClassData(String name) {

             // load the class data from the connection

              . . .

         }

     }


   从上面的代码可以看出通过重写findClass方法并在loadClassData中设定好加载.class 文件的路径可以实现自定义的加载机制。

假设我们已经定义好自己的加载器MyClassLoader,我们使用如下的代码便能够构造出例子中的类加载器树形结构。

MyClassLoader loadB = new MyClassLoader(“loadB”);

loadB.setPath(“D://app//serverlib”);

MyClassLoader loadA = new MyClassLoader(loadB,“loadA”);

loadB.setPath(“D://app//cientlib”);

MyClassLoader loadC = new MyClassLoader(null,”loadC”)//null代表父加载器为Bootstrap

loadC.setPath(“D://app//otherlib”);

我们一个测试类Sample 和一个测试类Dog进行加载测试。

Class Sample{

Static{

   New Dog();

}

}   


 

Class文件的存放路径如下:

     d:app/syslib/MyClassLoader.class

     d:app/serverlib/Sample.class

     d:app/clientlib/Dog.class

      d:app/otherlib/Sample.class,Dog.class 


 

TestCase1 :

Class clazz = loadA.loadClass(“Sample”);

Clazz.newInstance();

TestCase2 :

Class clazz = loadB.loadClass(“Sample”);

Clazz.newInstance();

TestCase3 :

Class clazz = loadC.loadClass(“Sample”);

Clazz.newInstance();

case1 由加载器的树形结构可以看出:loadA加载Sample时委托父亲LoadB加载Sample,由于再向上委托并不能加载Sample,所以 Sample LoadB app/serverlib 下加载,

对于Dog类,LoadA的所有父加载器都不能加载,所以有loadA app/clientlib下加载

 

case2 loadB app/serverlib中加载 Sample,由于loadB 与其父加载器都不能加载Dog,所以会抛出ClassNotfoundException。此时如果把Dog拷贝到 syslib下,Dog类就会被appCloader加载,而不会出现ClassNotFound错误。

 

Case3 LoadC直接委托Bootstrap加载Sample,由于无法加载只能有自己加载,所以Sample Dog都会从 app/otherlib/下加载.

假设 我们在MyClassLoader中写意给main方法测试

TestCase4 :

Class clazz = loadA.loadClass(“Sample”);

Sample sample  =  Clazz.newInstance();

此时会导致一个NoClassDefError,这主要是JVM的类加载器命名空间规则导致的,在jvm中子加载器的命令空间包含了父加载器加载的所有类,反过来则不成立,因为MyClassLoader类是有appLoader加载的,所以其看不见有LoadBloadA加载的类。

在这里顺便提一下,在一个类主动使用时,该类就开始起生命周期 加载,链接,初始化,使用,卸载。Jvm自带的加载器加载的Class是不能够被卸载的,只有用户自定义加载器加载的类才能被卸载,卸载机制是根据对类的引用计数情况而定,这与GC根据引用情况回收垃圾差不多。


appendix : 视频下载链接文件(电驴)

                  

 

0
2
分享到:
评论

相关推荐

    基于物联网智能化平台的智慧园区解决方案PPT(28页).pptx

    智慧园区,作为现代城市发展的新形态,旨在通过高度集成的信息化系统,实现园区的智能化管理与服务。该方案提出,利用智能手环、定制APP、园区管理系统及物联网技术,将园区的各类设施与设备紧密相连,形成一个高效、便捷、安全的智能网络。从智慧社区到智慧酒店,从智慧景区到智慧康养,再到智慧生态,五大应用板块覆盖了园区的每一个角落,为居民、游客及工作人员提供了全方位、个性化的服务体验。例如,智能手环不仅能实现定位、支付、求助等功能,还能监测用户健康状况,让科技真正服务于生活。而智慧景区的建设,更是通过大数据分析、智能票务、电子围栏等先进技术,提升了游客的游玩体验,确保了景区的安全有序。 尤为值得一提的是,方案中的智慧康养服务,展现了科技对人文关怀的深刻体现。通过智慧手环与传感器,自动感知老人身体状态,及时通知家属或医疗机构,有效解决了“空巢老人”的照护难题。同时,智慧生态管理系统的应用,实现了对大气、水、植被等环境要素的实时监测与智能调控,为园区的绿色发展提供了有力保障。此外,方案还提出了建立全域旅游营销平台,整合区域旅游资源,推动旅游业与其他产业的深度融合,为区域经济的转型升级注入了新的活力。 总而言之,这份智慧园区建设方案以其前瞻性的理念、创新性的技术和人性化的服务设计,为我们展示了一个充满智慧与活力的未来园区图景。它不仅提升了园区的运营效率和服务质量,更让科技真正融入了人们的生活,带来了前所未有的便捷与舒适。对于正在规划或实施智慧园区建设的决策者而言,这份方案无疑提供了一份宝贵的参考与启示,激发了他们对于未来智慧生活的无限遐想与憧憬。

    MES制造企业生产过程执行系统:全方位协同管理,提升生产效率与质量的信息化管理平台,MES制造企业生产过程执行系统:全面协同管理,提升生产效率与质量管理水平,mes制造企业生产过程执行系统,是一套面向

    MES制造企业生产过程执行系统:全方位协同管理,提升生产效率与质量的信息化管理平台,MES制造企业生产过程执行系统:全面协同管理,提升生产效率与质量管理水平,mes制造企业生产过程执行系统,是一套面向制造企业车间执行层的生产信息化管理系统。 MES 可以为企业提供包括制造数据管理、计划排产管理、生产调度管理、库存管理、质量管理、人力资源管理、工作中心 设备管理、工具工装管理、采购管理、成本管理、项目看板管理、生产过程控制、底层数据集成分析、上层数据集成分解等管理模块,为企业打造一个扎实、可靠、全面、可行的制造协同管理平台 ,MES制造企业生产过程执行系统;生产信息化管理;制造数据管理;计划排产管理;生产调度管理;库存管理;质量管理;人力资源管理;设备管理;数据集成分析,MES制造企业生产执行系统:全面协同管理平台助力制造企业高效运营

    C++指针与内存管理详解:避免常见错误及最佳实践

    内容概要:本文介绍了C++编程中常见指针错误及其解决方案,并涵盖了模板元编程的基础知识和发展趋势,强调了高效流操作的最新进展——std::spanstream。文章通过一系列典型错误解释了指针的安全使用原则,强调指针初始化、内存管理和引用安全的重要性。随后介绍了模板元编程的核心特性,展示了编译期计算、类型萃取等高级编程技巧的应用场景。最后,阐述了C++23中引入的新特性std::spanstream的优势,对比传统流处理方法展现了更高的效率和灵活性。此外,还给出了针对求职者的C++技术栈学习建议,涵盖了语言基础、数据结构与算法及计算机科学基础领域内的多项学习资源与实战练习。 适合人群:正在学习C++编程的学生、从事C++开发的技术人员以及其他想要深入了解C++语言高级特性的开发者。 使用场景及目标:帮助读者掌握C++中的指针规则,预防潜在陷阱;介绍模板元编程的相关技术和优化方法;使读者理解新引入的标准库组件,提高程序性能;引导C++学习者按照有效的路径规划自己的技术栈发展路线。 阅读建议:对于指针部分的内容,应当结合实际代码样例反复实践,以便加深理解和记忆;在研究模板元编程时,要从简单的例子出发逐步建立复杂模型的理解能力,培养解决抽象问题的能力;而对于C++23带来的变化,则可以通过阅读官方文档并尝试最新标准特性来加深印象;针对求职准备,应结合个人兴趣和技术发展方向制定合理的学习计划,并注重积累高质量的实际项目经验。

    VSC下垂控制策略仿真模型:基于MATLAB 2014a及更高版本的全面支持与应用实践,VSC下垂控制策略仿真模型MATLAB版本支持及功能解析,VSC下垂控制策略仿真模型,支持MATLAB2014a

    VSC下垂控制策略仿真模型:基于MATLAB 2014a及更高版本的全面支持与应用实践,VSC下垂控制策略仿真模型MATLAB版本支持及功能解析,VSC下垂控制策略仿真模型,支持MATLAB2014a及以上版本 ,VSC下垂控制策略; 仿真模型; MATLAB 2014a及以上版本; 核心关键词,MATLAB 2014a及以上版VSC下垂控制策略仿真模型研究

    信息技术知识赛系统设计与实现(代码+数据库+LW)

    摘  要 传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此,在计算机上安装信息技术知识赛系统软件来发挥其高效地信息处理的作用,可以规范信息管理流程,让管理工作可以系统化和程序化,同时,信息技术知识赛系统的有效运用可以帮助管理人员准确快速地处理信息。 信息技术知识赛系统在对开发工具的选择上也很慎重,为了便于开发实现,选择的开发工具为Eclipse,选择的数据库工具为Mysql。以此搭建开发环境实现信息技术知识赛系统的功能。其中管理员管理用户,新闻公告。 信息技术知识赛系统是一款运用软件开发技术设计实现的应用系统,在信息处理上可以达到快速的目的,不管是针对数据添加,数据维护和统计,以及数据查询等处理要求,信息技术知识赛系统都可以轻松应对。 关键词:信息技术知识赛系统;SpringBoot框架,系统分析,数据库设计

    蓝桥杯python准备建议.zip

    蓝桥杯是全国范围内具有广泛影响力的编程竞赛,对于准备参加蓝桥杯 Python 组比赛的同学来说,系统化的学习和针对性的训练是取得好成绩的关键。本项目是一份详细的蓝桥杯 Python 组准备建议,涵盖基础知识、算法与数据结构、刷题策略、实战演练以及心态调整等方面。

    Simulink与Carsim联合仿真实现轨迹跟踪,考虑侧倾、曲率变化及侧偏刚度修正,考虑侧倾和曲率变化的轨迹跟踪:Simulink与Carsim联合仿真修正侧偏刚度技术解析,轨迹跟踪,考虑侧倾和曲率

    Simulink与Carsim联合仿真实现轨迹跟踪,考虑侧倾、曲率变化及侧偏刚度修正,考虑侧倾和曲率变化的轨迹跟踪:Simulink与Carsim联合仿真修正侧偏刚度技术解析,轨迹跟踪,考虑侧倾和曲率变化,同时修正侧偏刚度 simulink carsim联合仿真 ,轨迹跟踪; 侧倾和曲率变化; 侧偏刚度修正; Simulink; CarSim联合仿真,Simulink联合仿真:车辆轨迹跟踪及侧倾、曲率修正研究

    Unity-游戏开发-模型资源-科幻武器

    总共包含 32 款 AAA 级科幻武器。四种武器类型,每种有 8 种不同的纹理变化! 所有内容均采用 PBR 材质,可直接用于开发游戏!

    Linux环境下PyTorch深度学习框架的搭建指南(Anaconda、CUDA、PyCharm、Jupyter)

    内容概要:本文详细介绍了在Ubuntu Linux上如何从零开始构建完整的PyTorch深度学习环境。步骤涵盖了镜像源配置、必需环境安装、Anaconda安装及配置,CUDA和显卡驱动安装,Anaconda虚拟环境创建,PyTorch安装及其相关依赖库的安装方法。对于安装过程中可能出现的一些问题提供了相应的解决方案。此外还简要涉及了Python环境的维护、IDE PyCharm的安装方法以及如何启动Anaconda附带的Jupyter Notebook。 适合人群:希望深入了解Linux操作系统下的机器学习环境配置过程的初级开发者和技术爱好者,特别是有兴趣应用PyTorch从事科研项目的人群。 使用场景及目标:旨在帮助读者掌握基于Ubuntu平台配置高性能PyTorch环境的具体流程,从而能快速投入到实际开发工作中;同时为未来扩展更多AI/ML应用打下坚实基础。 其他说明:本教程假设读者已经有一定Linux命令行操作基础,并且拥有基本的Python编程能力。教程重点在于具体的技术步骤而非理论讲解,对于每一阶段都附带有详尽的操作截图辅助理解。

    IEEE9节点系统Simulink仿真:实现潮流计算与稳定性分析的电力仿真模型,基于Matlab Simulink的IEEE9节点系统仿真:潮流计算与稳定性分析,IEEE9节点系统Simulink仿真

    IEEE9节点系统Simulink仿真:实现潮流计算与稳定性分析的电力仿真模型,基于Matlab Simulink的IEEE9节点系统仿真:潮流计算与稳定性分析,IEEE9节点系统Simulink仿真 1.基础功能:基于Matlab simulink平台搭建IEEE9节点仿真模型,对电力系统进行潮流计算(与编程用牛拉法计算潮流结果一致) 2.拓展功能: 可在该IEEE9节系统仿真模型上进行暂态、静态稳定性仿真分析。 ,IEEE9节点系统; Simulink仿真; 潮流计算; 牛拉法; 暂态稳定性仿真分析; 静态稳定性仿真分析,基于Simulink的IEEE9节点系统仿真:潮流计算与稳定性分析

    欧姆龙NJ/NX系列PLC ST语言编程:Modbus RTU读写轮询与八从站通讯集成,搭配CF105模块使用,含FB功能块调用案例参考,欧姆龙NJ/NX系列PLC的ST语言编程:集成Modbus R

    欧姆龙NJ/NX系列PLC ST语言编程:Modbus RTU读写轮询与八从站通讯集成,搭配CF105模块使用,含FB功能块调用案例参考,欧姆龙NJ/NX系列PLC的ST语言编程:集成Modbus RTU读写轮询与八个485从站通讯功能,搭配CF105模块使用,含通讯FB功能块与主程序调用案例,欧姆龙NJ,NX系列plc,ST语言编写,该程序包含ModbusRTU的读写轮询,带八个485从站,此程序必须搭配欧姆龙CF105模块才能使用。 通讯的程序都封装成FB功能块可以直接调用,主程序有调用案例参考 ,欧姆龙NJ; NX系列PLC; ST语言编写; ModbusRTU读写轮询; 485从站; 欧姆龙CF105模块; 通讯FB功能块; 主程序调用案例。,欧姆龙PLC ST语言Modbus RTU读写轮询程序:CF105模块八从站通讯应用

    数学建模相关主题资源2

    数学建模相关主题资源2

    Go语言教程&案例&相关项目资源

    Go语言教程&案例&相关项目资源

    企业微信会话存档+deepseek智能预警

    ### **软件更新公告:AI会话存档与分析功能全新上线!** 亲爱的用户, 我们很高兴地宣布,本次软件更新带来了全新的 **AI会话存档与分析功能**,旨在帮助企业更好地管理员工与客户的沟通内容,提升服务质量,优化运营效率。以下是本次更新的详细内容: --- #### **1. 会话存档** - **功能描述**:系统将自动拉取员工与客户的文本聊天内容,并完整存档,方便随时查阅。 - **使用场景**: - 查看员工与客户的历史沟通记录。 - 审计聊天内容,确保合规性。 - 为客户问题提供追溯依据。 --- #### **2. AI会话报告** - **功能描述**:结合 **DeepSeek AI** 技术,对员工发送给客户的聊天内容进行智能分析,判断是否存在以下行为: - **敲单行为**:识别员工是否诱导客户下单或进行不必要的推销。 - **辱骂客户**:检测聊天内容中是否存在不当言辞或辱骂行为。 - **索要回扣/红包**:分析员工是否向客户索要回扣、红包或其他不当利益。 - **使用场景**: - 实时监控员工与客户的沟通质量。

    点餐系统.zip

    毕业设计

    并联型APF有源电力滤波器Matlab Simulink仿真研究:涉及dq和αβ坐标系谐波无功检测与SVPWM调制方式的仿真介绍文档,基于Matlab Simulink仿真的并联型APF有源电力滤波器

    并联型APF有源电力滤波器Matlab Simulink仿真研究:涉及dq和αβ坐标系谐波无功检测与SVPWM调制方式的仿真介绍文档,基于Matlab Simulink仿真的并联型APF有源电力滤波器谐波及无功检测技术研究,包含PI控制与SVPWM调制方式的深入探讨,并联型APF 有源电力滤波器 Matlab Simulink仿真 *dq FBD谐波 无功检测 *两相旋转坐标系(dq)、两相静止坐标系(αβ)下的PI控制 *SVPWM调制方式 (含仿真介绍文档) ,核心关键词:并联型APF; 有源电力滤波器; Matlab Simulink仿真; dq FBD谐波无功检测; 两相旋转坐标系PI控制; 两相静止坐标系PI控制; SVPWM调制方式。,基于Matlab Simulink仿真的并联型APF有源电力滤波器研究:dq FBD谐波与无功检测的PI控制及SVPWM调制方式

    Swift编程语言详解:从基础语法到Swift 6新特性及跨平台发展趋势

    内容概要:本文详细介绍了苹果公司推出的编程语言 Swift,涵盖其基本概念、语法特点、环境搭建以及从 Swift 3 到 Swift 6 的重要更新与发展历程。Swift 是一门专注于 iOS、macOS、watchOS 和 tvOS 开发的语言,语法简洁,比 Objective-C 更易于学习和使用。文章首先简要介绍了 Swift 的基础知识,包括变量和常量、基本数据类型、控制流语句、函数定义、类和结构体,以及高级特性如可选类型、强制解包、可选绑定、闭包和协议。接着探讨了 Swift 的历史演变及其在不同操作系统(Linux 和 Windows)上的应用,尤其是 Swift 在 2015 年开源后的快速发展。最新的 Swift 6 版本引入了诸如编译时数据竞争保护等多项创新特性,极大地提升了并发编程的安全性和易用性。最后讨论了开发者的看法及其应用场景的可能性。 适合人群:具有一定编程基础的研发人员,尤其是那些有兴趣深入了解苹果生态系统或跨平台开发的技术爱好者。 使用场景及目标:帮助读者快速掌握 Swift 编程语言的核心概念和技术栈;指导初学者如何配置和使用 Xcode 编写首个 Swift 应用程序;分析最新发布的 Swift 6 更新亮点,并提供从 Swift 5 迁移到 Swift 6 期间可能遇到的问题及解决方法。 阅读建议:建议新手先掌握基本的 Swift 语法和面向对象编程思想再深入研究高级主题;同时密切关注官方发布的最新动态和支持资料,及时更新对 Swift 技术的认知;针对想要过渡到 Swift 6 的团队,务必进行充分的学习准备并在实践中积累经验以克服潜在困难。此外,考虑到 Swift 正逐渐扩展到非苹果平台的应用开发中,请对 Swift 在不同平台下的表现保持敏感并积极探索跨平台解决方案。

    024.JSP+SQL网上教学系统.zip

    毕业设计

    BLDC无刷直流电机与PMSM永磁同步电机的传感器/无传感器驱动算法全攻略:涵盖STM32F1实战代码与原理图,BLDC无刷直流电机与PMSM永磁同步电机的传感器/无传感器驱动算法集合,STM32F1

    BLDC无刷直流电机与PMSM永磁同步电机的传感器/无传感器驱动算法全攻略:涵盖STM32F1实战代码与原理图,BLDC无刷直流电机与PMSM永磁同步电机的传感器/无传感器驱动算法集合,STM32F1代码全解析与分享,BLDC无刷直流电机和PMSM永磁同步电机 可提供所有代码中所有算法的,每个代码都亲自验证过。 基于STM32F1的有传感器和无传感驱动 直流无刷电机有传感器和无传感驱动程序, 无传感的实现是基于反电动势过零点实现的,有传感的霍尔实现。 永磁同步电机有感无感程序,有感为霍尔FOC和编码器方式, 无感为滑模观测器方式。 有原理图和文档,识的赶紧,物超所值。 提供里面所有代码,所有算法的。 提供里面所有代码,所有算法的。 ,BLDC无刷直流电机; PMSM永磁同步电机; 算法验证; STM32F1驱动; 有传感器驱动; 无传感驱动; 反电动势过零点; 霍尔实现; 霍尔FOC; 编码器方式; 换滑模观测器; 原理图; 文档。,基于STM32F1的BLDC与PMSM电机驱动解决方案:全算法代码与原理图详解

    永磁同步电机矢量控制仿真研究:无SVPWM发波策略分析,永磁同步电机矢量控制仿真研究:不含SVPWM发波的算法优化分析,永磁同步电机矢量控制仿真,不带SVPWM发波 ,永磁同步电机; 矢量控制; 仿

    永磁同步电机矢量控制仿真研究:无SVPWM发波策略分析,永磁同步电机矢量控制仿真研究:不含SVPWM发波的算法优化分析,永磁同步电机矢量控制仿真,不带SVPWM发波 ,永磁同步电机; 矢量控制; 仿真; 不带SVPWM发波; 控制系统,永磁同步电机矢量控制仿真:非SVPWM发波技术探讨

Global site tag (gtag.js) - Google Analytics