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

JVM字节码与类的加载——class文件结构

文章目录

  • 1、概述
    • 1.1、class文件的跨平台性
    • 1.2、编译器分类
    • 1.3、透过字节码指令看代码细节
  • 2、虚拟机的基石:class文件
    • 2.1、字节码指令
    • 2.2、解读字节码方式
  • 3、class文件结构
    • 3.1、魔数:class文件的标识
    • 3.2、class文件版本号
    • 3.3、常量池:存放所有常量
    • 3.4、访问标识

一段Java程序编写完成后,会被存储到以.java为后缀的源文件中,源文件会被编译器编译为以.class为后缀的二进制文件,之后以.class为后缀的二进制文件会经由类加载器加载至内存中。本贴要讲的重点就是以.class为后缀的二进制文件,也简称为class文件或者字节码文件。接下来将会介绍class文件的详细结构,以及如何解析class文件。

1、概述

1.1、class文件的跨平台性

Java是一门跨平台的语言,也就是我们常说的“Write once,run anywhere”,意思是当Java代码被编译成字节码后,就可以在不同的平台上运行,而无须再次编译。但是现在这个优势不再那么吸引人了,Python、PHP、Perl、Ruby、Lisp等语言同样有强大的解释器。跨平台几乎成为一门开发语言必备的特性。

虽然很多语言都有跨平台性,但是JVM却是一个跨语言的平台。JVM不和包括Java在内的任何语言绑定,它只与class文件这种特定的二进制文件格式关联。无论使用何种语言开发软件,只要能将源文件编译为正确的class文件,那么这种语言就可以在JVM上执行,如下图所示:
在这里插入图片描述
比如Groovy语言、Scala语言等。可以说规范的class文件结构,就是JVM的基石、桥梁。

JVM有很多不同的实现,但是所有的JVM全部遵守Java虚拟机规范,也就是说所有的JVM环境都是一样的,只有这样class文件才可以在各种JVM上运行。在Java发展之初,设计者就曾经考虑并实现了让其他语言运行在Java虚拟机之上的可能性,他们在发布规范文档的时候,也刻意把Java的规范拆分成了Java语言规范及Java虚拟机规范。官方虚拟机规范如下图所示:
在这里插入图片描述
想要让一个Java程序正确地运行在JVM中,Java源文件就必须要被编译为符合JVM规范的字节码。前端编译器就是负责将符合Java语法规范的Java代码转换为符合JVM规范的class文件。常用的javac就是一种能够将Java源文件编译为字节码的前端编译器。javac编译器在将Java源文件编译为一个有效的class文件过程中经历了4个步骤,分别是词法解析、语法解析、语义解析以及生成字节码。

Oracle的JDK软件中除了包含将Java源文件编译成class文件外,还包含JVM的运行时环境。如下图所示:
在这里插入图片描述
Java源文件(Java Source)经过编译器编译为class文件,之后class文件经过ClassLoader加载到虚拟机的运行时环境。需要注意的是ClassLoader只负责class文件的加载,至于class文件是否可以运行,则由执行引擎决定。

1.2、编译器分类

Java源文件的编译结果是字节码,那么肯定需要有一种编译器将Java源文件编译为class文件,承担这个重要责任的就是配置在path环境变量中的javac编译器。javac是一种能够将Java源文件编译为字节码的前端编译器。

HotSpot VM并没有强制要求前端编译器只能使用javac来编译字节码,其实只要编译结果符合JVM规范都可以被JVM所识别。

在Java的前端编译器领域,除了javac,还有一种经常用到的前端编译器,那就是内置在Eclipse中的ECJ(Eclipse Compiler for Java)编译器。和javac的全量式编译不同,ECJ是一种增量式编译器。

在Eclipse中,当开发人员编写完代码,使用Ctrl+S快捷键保存代码时,ECJ编译器会把未编译部分的源码逐行进行编译,而不是每次都全量编译。因此ECJ的编译效率更高。

ECJ不仅是Eclipse的默认内置前端编译器,在Tomcat中同样也是使用ECJ编译器来编译jsp文件。由于ECJ编译器是采用GPLv2的开源协议进行开源的,所以大家可以在Eclipse官网下载ECJ编译器的源码进行二次开发。另外,IntelliJ IDEA默认使用javac编译器。

我们把不同的编程语言类比为不同国家的语言,它们经过前端编译器处理之后,都变成同一种class文件。如下图所示:
在这里插入图片描述
前端编译器把各个国家的“你好”编译为一样的“乌拉库哈吗哟”,这个“乌拉库哈吗哟”就好比class文件中的内容。class文件对于执行引擎是可以识别的,所以JVM是跨语言的平台,其中起关键作用的就是前端编译器。JIT编译器可以对程序做栈上分配、同步省略等优化。为了区别前面讲的javac,把JIT称为后端编译器。

除了上面提到的前端编译器和后端编译器,还有AOT编译器和Graal编译器。

1.3、透过字节码指令看代码细节

通过学习class文件,可以查看代码运行的详细信息。代码清单如下所示,测试不同Integer变量是否相等。
在这里插入图片描述
运行结果如下:

     truefalse

显而易见,两次运行结果并不相同。定义的变量是Integer类型,采用的是直接赋值的形式,并没有通过某一个方法进行赋值,所以无法看到代码底层的执行逻辑是怎样的,那么只能通过查看class文件来分析问题原因。通过IDEA中的插件jclasslib查看class文件,如下图所示:
在这里插入图片描述
class文件中包含很多字节码指令,分别表示程序代码执行期间用到了哪些指令。这里仅说一下Integer i1 = 10语句执行的是<java/lang/Integer.valueOf>方法,也就是Integer类中的valueOf方法,我们查看源代码如下图所示:
在这里插入图片描述
可以发现对Integer赋值的时候,通过i和IntegerCache类高位值和低位值的比较,判断i是否直接从IntegerCache内cache数组获取数据。IntegerCache类的低位值为-128,高位值为127。如果赋值在低位值和高位值范围内,则返回IntegerCache内cache数组中的同一个值;否则,重新创建Integer对象。这也是为什么当Integer变量赋值为10的时候输出为true,Integer变量赋值为128的时候输出为false。

2、虚拟机的基石:class文件

源代码经过编译器编译之后生成class文件,字节码是一种二进制的文件,它的内容是JVM的指令,其不像C、C++经由编译器直接生成机器码。

2.1、字节码指令

JVM的指令由一个字节长度的、代表着某种特定操作含义的操作码(opcode)以及跟随其后的零至多个代表此操作所需参数的操作数(operand)所构成。虚拟机中许多指令并不包含操作数,只有一个操作码。如下图所示:
在这里插入图片描述
其中aload_0是操作码,没有操作数。bipush 30中的bipush是操作码,30是操作数。

2.2、解读字节码方式

由于class文件是二进制形式的,所以没办法直接打开查看,需要使用一些工具将class文件解析成我们可以直接阅读的形式。解析方式主要有以下三种。

1、使用第三方文本编辑工具:我们常用的第三方文本编辑工具有Notepad++和Binary Viewer。以NotePad++为例,需要在插件中安装“HEX-Editor”插件。安装完插件之后,打开一个class文件,如下图所示:
在这里插入图片描述
展示结果为乱码。如果想要以十六进制视图展示,单击“插件”→“HEX-Editor”→“View in HEX”即可,如下图所示:
在这里插入图片描述
2、使用javap指令:JDK自带的解析工具。

3、jclasslib工具:jclasslib工具在解析class文件时,已经进行了二进制数据的“翻译”工作,可以更直观地反映class文件中的数据。各位读者可以下载安装jclasslib Bytecode viewer客户端工具或者在IDEA的插件市场安装jclasslib插件,如下图所示:
在这里插入图片描述

3、class文件结构

任何一个class文件都对应着唯一一个类或接口的定义信息,但是并不是所有的类或接口都必须定义在文件中,它们也可以通过类加载器直接生成。也就是说class文件实际上并不一定以磁盘文件的形式存在。class文件是一组以8位字节为基础单位的二进制流,它的结构不像XML等描述语言,由于它没有任何分隔符号,所以在其中的数据项,无论是字节顺序还是数量,都是被严格限定的,哪个字节代表什么含义,长度是多少,先后顺序如何,都不允许改变,就好像一篇没有标点符号的文章。这使得整个class文件中存储的内容几乎全部是程序运行的必要数据,没有空隙存在。class文件格式采用一种类似于C语言结构体的伪结构来存储数据,这种伪结构只有无符号数和表两种数据类型。

无符号数属于基本的数据类型,以u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节和8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照UTF-8编码构成字符串值。对于字符串,则使用u1数组进行表示。

表是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性地以“_info”结尾。表用于描述有层次关系的复合结构的数据,整个class文件本质上就是一张表。由于表没有固定长度,所以通常会在其前面加上长度说明。在学习过程中,只要充分理解了每一个class文件的细节,甚至可以自己反编译出Java源文件。

class文件的结构并不是一成不变的,随着JVM的不断发展,总是不可避免地会对class文件结构做出一些调整,但是其基本结构和框架是非常稳定的。class文件的整体结构如下表所示:
在这里插入图片描述
官方对class文件结构的详细描述如下图所示:
在这里插入图片描述
上面class文件的结构解读如下表所示:
在这里插入图片描述
下面我们按照上面的顺序逐一解读class文件结构。首先编写一段简单的代码,对照上面的结构表来分析class文件,代码清单如下所示:
在这里插入图片描述

这段代码很简单,只有一个成员变量num和一个方法fun()。将源文件编译为class文件,我们使用命令javac编译,如下所示:

     javac ClassFileDemo.java

上面命令的执行结果是生成一个ClassFileDemo.class文件。使用安装好HEX-Editor插件的Notepad++打开ClassFileDemo.class文件,结果如下图所示:
在这里插入图片描述
篇幅原因展示部分截图,可以看到每个字节都是十六进制数字,通过分析每个字节来解析class文件。

3.1、魔数:class文件的标识

每个class文件开头的4个字节的无符号整数称为魔数(Magic Number)。魔数的唯一作用是确定class文件是否有效合法,也就是说魔数是class文件的标识符。魔数值固定为0xCAFEBABE,如下图框中所示:
在这里插入图片描述
之所以使用CAFEBABE,可以从Java的图标(一杯咖啡)窥得一二。

如果一个class文件不以0xCAFEBABE开头,JVM在文件校验的时候就会直接抛出以下错误的错误。
在这里插入图片描述
比如将ClassFileDemo.java文件后缀改成ClassFileDemo.class,然后使用命令行解释运行,就报出上面的魔数不对的错误。

使用魔数而不是扩展名识别class文件,主要是基于安全方面的考虑,因为文件扩展名可以随意改动。除了Java的class文件以外,其他常见的文件格式内部也会有类似的设计手法,比如图片格式gif或者jpeg等在头文件中都有魔数。

3.2、class文件版本号

紧接着魔数存储的是class文件的版本号,同样也是4个字节。第5个和第6个字节所代表的含义是class文件的副版本号minor_version,第7个和第8个字节是class文件的主版本号major_version。它们共同构成了class文件的版本号,例如某个class文件的主版本号为M,副版本号为m,那么这个class文件的版本号就确定为M.m。版本号和Java编译器版本的对应关系如下表所示:
在这里插入图片描述
Java的版本号是从45开始的,JDK 1.1之后每发布一个JDK大版本,主版本号向上加1。当虚拟机JDK版本为1.k(k≥2)时,对应的class文件版本号的范围为45.0到44+k.0之间(含两端)。字节码指令集多年不变,但是版本号每次发布都会变化。

不同版本的Java编译器编译的class文件对应的版本是不一样的。目前,高版本的JVM可以执行由低版本编译器生成的class文件,可以理解为向下兼容。但是低版本的JVM不能执行由高版本编译器生成的class文件。一旦执行,JVM会抛出java.lang.UnsupportedClass VersionError异常。在实际应用中,由于开发环境和生产环境的不同,可能会导致该问题的发生。因此,需要我们在开发时,特别注意开发环境的JDK版本和生产环境中的JDK版本是否一致。

上面的ClassFileDemo.class文件使用JDK8版本编译而成,第5个字节到第8个字节如下图所示:
在这里插入图片描述

3.3、常量池:存放所有常量

紧跟在版本号之后的是常量池中常量的数量(constant_pool_count)以及若干个常量池表项(constant_pool[])。常量池是class文件中内容最为丰富的区域之一。常量池表项用于存放编译时期生成的各种字面量(Literal)和符号引用(Symbolic References),这部分内容在经过类加载器加载后存放在方法区的运行时常量池中存放。常量池对于class文件中的字段和方法解析起着至关重要的作用。随着JVM的不断发展,常量池的内容也日渐丰富。可以说,常量池是整个class文件的基石。

1、constant_pool_count(常量池计数器)
由于常量池的数量不固定,时长时短,所以需要放置两个字节(u2类型)来表示常量池容量计数值。常量池容量计数器从1开始计数,constant_pool_count=1表示常量池中有0个常量项。通常我们写代码时都是从0开始的,但是这里的常量池计数器却是从1开始,因为它把第0项常量空出来了,这是为了满足某些指向常量池的索引值的数据在特定情况下需要表达“不引用任何一个常量池项目”的含义,这种情况可用索引值0来表示。如下图所示:
在这里插入图片描述

第9个字节和第10个字节表示常量池计数器,其值为0x001f,换算为十进制为31,需要注意的是,实际上只有30项常量,索引范围是1~30。

我们也可以通过jclasslib插件来查看常量池数量,如下图所示,可以看到一共有30个常量。
在这里插入图片描述
2、constant_pool[](常量池)
常量池是一种表结构,从1到constant_pool_count–1为索引。常量池主要存放字面量和符号引用两大类常量。常量池包含了class文件结构及其子结构中引用的所有字符串常量、类或接口名、字段名和其他常量。常量池中的每一项常量的结构都具备相同的特征,那就是每一项常量入口都是一个u1类型的标识,该标识用于确定该项的类型,这个字节称为tag byte(标识字节),如下图所示:
在这里插入图片描述
一旦JVM获取并解析这个标识,JVM就会知道在标识后的常量类型是什么。常量池中的每一项都是一个表,其项目类型共有14种,下表列出了所有常量项的类型和对应标识的值,比如当标识值为1时,表示该常量的类型为CONSTANT_utf8_info。
在这里插入图片描述
这14种类型的结构各不相同,各个类型的结构如下表所示:
在这里插入图片描述
在这里插入图片描述
根据上表中对每个类型的描述,我们可以知道每个类型是用来描述常量池中的字面量、符号引用,比如CONSTANT_Integer_info是用来描述常量池中字面量信息,而且只是整型字面量信息。标识值为15、16、18的常量项类型是用来支持动态语言调用的,它们在JDK7时加入。下面按照标识的大小顺序分别进行介绍。

  • (1)CONSTANT_Utf8_info用于表示字符常量的值。
  • (2)CONSTANT_Integer_info和CONSTANT_Float_info表示4字节(int和float)的数值常量。
  • (3)CONSTANT_Long_info和CONSTANT_Double_info表示8字节(long和double)的数值常量;在class文件的常量池表中,所有的8字节常量均占两个表项的空间。如果一个CONSTANT_Long_info或CONSTANT_Double_info的项在常量池表中的索引位n,则常量池表中下一个可用项的索引为n+2,此时常量池表中索引为n+1的项仍然有效但必须视为不可用的。
  • (4)CONSTANT_Class_info用于表示类或接口。
  • (5)CONSTANT_String_info用于表示String类型的常量对象。
  • (6)CONSTANT_Fieldref_info、CONSTANT_Methodref_info表示字段、方法。
  • (7)CONSTANT_InterfaceMethodref_info表示接口方法。
  • (8)CONSTANT_NameAndType_info用于表示字段或方法,但是和之前的3个结构不同,CONSTANT_NameAndType_info没有指明该字段或方法所属的类或接口。
  • (9)CONSTANT_MethodHandle_info用于表示方法句柄。
  • (10)CONSTANT_MethodType_info表示方法类型。
  • (11)CONSTANT_InvokeDynamic_info用于表示invokedynamic指令所用到的引导方法(Bootstrap Method)、引导方法所用到的动态调用名称(Dynamic Invocation name)、参数和返回类型,并可以给引导方法传入一系列称为静态参数(Static Argument)的常量。

这14种表(或者常量项结构)的共同点是表开始的第一位是一个u1类型的标识位(tag),代表当前这个常量项使用的是哪种表结构,即哪种常量类型。在常量池列表中,CONSTANT_Utf8_info常量项是一种使用改进过的UTF-8编码格式来存储诸如文字字符串、类或者接口的全限定名、字段或者方法的简单名称以及描述符等常量字符串信息。这14种常量项结构还有一个特点是,其中13个常量项占用的字节固定,只有CONSTANT_Utf8_info占用字节不固定,其大小由length决定。因为从常量池存放的内容可知,其存放的是字面量和符号引用,最终这些内容都会是一个字符串,这些字符串的大小是在编写程序时才确定,比如定义一个类,类名可以取长取短,所以在代码源文件没编译前,大小不固定;代码源文件编译后,可以通过utf-8编码知道其长度。

常量池可以理解为class文件之中的资源仓库,它是class文件结构中与其他项目关联最多的数据类型(后面讲解的很多数据结构都会指向此处),也是占用class文件空间最大的数据项目之一。

Java代码在进行javac编译的时候,并不像C和C++那样有“连接”这一步骤,而是在虚拟机加载class文件的时候进行动态链接。也就是说,在class文件中不会保存各个方法、字段的最终内存布局信息,因此这些字段、方法的符号引用不经过运行期转换的话无法得到真正的内存入口地址,也就无法直接被虚拟机使用。当虚拟机运行时,需要从常量池获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址之中。本章先弄清楚class文件中常量池中的字面量符号引用。

(1)字面量和符号引用。常量池主要存放两大类常量字面量和符号引用。字面量和符号引用的具体定义如下表所示:
在这里插入图片描述
字面量很容易理解,例如定义String str = “xiaoyang”和final int NUM = 10,其中atguigu和10都是字面量,它们都放在常量池中,注意没有存放在内存中。符号引用包含类和接口的全限定名、简单名称、描述符三种常量类型。

  • ①类和接口的全限定名:com/yung/ClassFileDemo就是类的全限定名,仅仅是把包名的“.”替换成“/”,为了使连续的多个全限定名之间不产生混淆,在使用时最后一般会加入一个“;”表示全限定名结束。
  • ②简单名称:简单名称是指没有类型和参数修饰的方法或者字段名称。
  • ③描述符:描述符的作用是用来描述字段的数据类型、方法的参数列表(包括数量、类型以及顺序)和返回值。

(2)常量解读:针对ClassFileDemo.class文件,我们解读其中的常量池中存储的信息。首先是第一个常量,其标识位如下图所示:
在这里插入图片描述

其值为0x0a,即10,查找表可知,其对应的项目类型为CONSTANT_Methodref_info,即类中方法的符号引用,其结构如下图所示:
在这里插入图片描述
可以看到标识后面还有4个字节的内容,分别为两个索引项,如下图所示:
在这里插入图片描述
其中前两位的值为0x0006,即6,指向常量池第6项的索引;后两位的值为0x0013,即19,指向常量池第19项的索引。至此,常量池中第一个常量项解析完毕。再来看下第二个常量,其标识位如下图所示:
在这里插入图片描述
标识值为0x09,即9,查找表可知,其对应的项目类型为CONSTANT_Fieldref_info,即字段的符号引用,其结构如下图所示:
在这里插入图片描述
同样后面也有4字节的内容,分别为两个索引项,如下图所示:
在这里插入图片描述
同样也是4字节,前后都是两个索引。分别指向第5项的索引和第20项的索引。后面常量项就不一一去解读了,这样的class文件解读起来既费力又费神,还很有可能解析错误。我们可以使用“javap -verbose ClassFileDemo.class”命令去查看class文件,如下图所示:
在这里插入图片描述
可以看到,常量池中总共有30个常量项,第一个常量项指向常量池第6项的索引以及指向常量池第19项的索引,第二个常量项指向常量池第5项的索引和指向常量池第20项的索引。和我们上面按照字节码原文件解析结果一样。虽然使用javap命令很方便,但是通过手动分析才知道这个结果是怎么出来的,做到知其然也知其所以然。

3.4、访问标识

常量池后紧跟着访问标识。访问标识(access_flag)描述的是当前类(或者接口)的访问修饰符,如public、private等标识使用两个字节表示,用于识别一些类或者接口层次的访问信息,识别当前Java源文件属性是类还是接口;是否定义为public类型;是否定义为abstract类型;如果是类的话,是否被声明为final等。访问标识的类型如下表所示:
在这里插入图片描述

比如当标识值为0x0001的时候,访问标识的类型是public。

相关文章:

JVM字节码与类的加载——class文件结构

文章目录 1、概述1.1、class文件的跨平台性1.2、编译器分类1.3、透过字节码指令看代码细节 2、虚拟机的基石&#xff1a;class文件2.1、字节码指令2.2、解读字节码方式 3、class文件结构3.1、魔数&#xff1a;class文件的标识3.2、class文件版本号3.3、常量池&#xff1a;存放所…...

小程序如何通过公众号发送新订单提醒

当客户在小程序上下单后&#xff0c;公众号会发送订单通知&#xff0c;这可以让管理员及时获知用户下单情况&#xff0c;方便及时处理订单和提供服务。下面是具体介绍如何设置公众号来发送订单服务通知。 方式一&#xff1a;通过采云公众号发送订单通知 此种方式是默认的通知…...

聊聊公众号最让我不爽的两个痛点

本文首发于 Python猫 微信公众号最让我不爽的地方有两个&#xff0c;而且有很多人虽然也不爽&#xff0c;却不知道原因。 本文想聊聊公众号的两个痛点&#xff0c;因为我经常收到私信问这两个问题&#xff0c;本文算是一次集中的回复吧。 第一个不爽的点是公众号会屏蔽外链&…...

【leetCode】2810. 故障键盘

文章目录 [2810. 故障键盘](https://leetcode.cn/problems/faulty-keyboard/)思路一&#xff1a;模拟代码&#xff1a;思路二&#xff1a;双端队列代码&#xff1a; 2810. 故障键盘 思路一&#xff1a;模拟 用StringBuilder来拼贴字符遍历字符串&#xff0c;如果遇到i,对拼贴好…...

xshell7连接ubuntu18.04

&#x1f3a1;导航小助手&#x1f3a1; 1.查看ubuntu IP2.开启openssh-server3.静态IP设置4.Xshell连接 1.查看ubuntu IP 输入下面命令查看IP ifconfig -a可以看到网卡是ens33&#xff0c;IP为192.168.3.180。 2.开启openssh-server 1、执行下句&#xff0c;下载SSH服务 s…...

真正的力量:实力与人际关系的平衡艺术

在当今社会&#xff0c;人们常常在追求个人发展和建立良好人际关系之间寻找平衡。有一种观点认为&#xff0c;“没有实力&#xff0c;就不要对别人好。不然&#xff0c;很容易被定义为讨好。”这句话在一定程度上揭示了实力与人际关系之间的微妙联系。本文将探讨这一观点的深层…...

Acwing.1388 游戏(区间DP对抗思想)

题目 玩家一和玩家二共同玩一个小游戏。 给定一个包含 N个正整数的序列。 由玩家一开始&#xff0c;双方交替行动。 每次行动可以在数列的两端之中任选一个数字将其取走&#xff0c;并给自己增加相应数字的分数。&#xff08;双初始分都是 0分&#xff09; 当所有数字都被…...

Numpy数组转换为csv文件

参考&#xff1a;Converting Numpy Array to CSV 在数据分析和处理中&#xff0c;经常会涉及到将数据从一个形式转换为另一个形式的操作。 其中&#xff0c;将Numpy数组转换为csv文件是一种常见的操作&#xff0c;因为csv文件是一种通用的数据存储格式&#xff0c;方便与其他软…...

替代安全指标(Surrogate Safety Measures (SSM) )

替代安全措施&#xff08;Surrogate Safety Measures (SSM) &#xff09;用于从数据中寻找接近碰撞&#xff0c;或可能发生&#xff08;但实际没有发生&#xff09;的碰撞事件。 SSM的两个合格标准&#xff1a; &#xff08;1&#xff09;它应该来自与碰撞直接相关的交通冲突&…...

usb_camera传输视频流编码的问题记录!

前言&#xff1a; 大家好&#xff0c;今天给大家分享的内容是&#xff0c;一个vip课程付费的朋友&#xff0c;在学习过程中遇到了一个usb采集的视频数据流&#xff0c;经过ffmpeg编码&#xff0c;出现了问题&#xff1a; 问题分析&#xff1a; 其实这个问题不难&#xff0c;关键…...

Linux安装nginx保姆级教程

文章目录 前言一、nginx安装&#xff08;保姆级教程&#xff09;1.安装nginx依赖2.安装wget3.创建nginx安装目录4.下载nginx5.查看下载好的nginx6.解压缩7.查看当前目录下的文件→进入nginx-1.8.0目录→查看当前目录下的文件8.安装nginx9.查看nginx安装目录并启动nginx10.网络请…...

leetcode-判断二分图

. - 力扣&#xff08;LeetCode&#xff09; 存在一个 无向图 &#xff0c;图中有 n 个节点。其中每个节点都有一个介于 0 到 n - 1 之间的唯一编号。给你一个二维数组 graph &#xff0c;其中 graph[u] 是一个节点数组&#xff0c;由节点 u 的邻接节点组成。形式上&#xff0c…...

算法day30 回溯6

332 重新安排行程 给你一份航线列表 tickets &#xff0c;其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从 JFK&#xff08;肯尼迪国际机场&#xff09;出发的先生&#xff0c;所以该行程必须从 JFK …...

分享three.js实现乐高小汽车

前言 Web脚本语言JavaScript入门容易&#xff0c;但是想要熟练掌握却需要几年的学习与实践&#xff0c;还要在弱类型开发语言中习惯于使用模块来构建你的代码&#xff0c;就像小时候玩的乐高积木一样。 应用程序的模块化理念&#xff0c;通过将实现隐藏在一个简单的接口后面&a…...

gpt的构造和原理

gpt是序列预测模型。 问答是通过确定问答格式样本训练出来的&#xff01;比如“Q&#xff1a;xxxx.A:xxx"本质还是根据前面的序列预测后面的序列。在自回归训练过程中&#xff0c;文本序列&#xff08;可能包含问题和紧随其后的答案&#xff09;被视为一个整体输入到模型…...

基于springboot实现教师人事档案管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现IT技术交流和分享平台系统演示 摘要 我国科学技术的不断发展&#xff0c;计算机的应用日渐成熟&#xff0c;其强大的功能给人们留下深刻的印象&#xff0c;它已经应用到了人类社会的各个层次的领域&#xff0c;发挥着重要的不可替换的作用。信息管理作为计算…...

K8S之Job和CronJob控制器

这里写目录标题 Job概念适用场景使用案例 CronJob概念适用场景使用案例 Job 概念 Job控制器用于管理Pod对象运行一次性任务&#xff0c;例如&#xff1a;对数据库备份&#xff0c;可以直接在k8s上启动一个mysqldump备份程序&#xff0c;也可以启动一个pod&#xff0c;这个pod…...

基于SSM的基于个人需求和地域特色的外卖推荐系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的基于个人需求和地域特色的外卖推荐系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…...

哈佛大学商业评论 --- 第三篇:真实世界中的增强现实

AR将全面融入公司发展战略&#xff01; AR将成为人类和机器之间的新接口&#xff01; AR将成为人类的关键技术之一&#xff01; 请将此文转发给您的老板&#xff01; --- 本文作者&#xff1a;Michael E.Porter和James E.Heppelmann 虽然物理世界是三维的&#xff0c;但大…...

华为ICT七力助推文化产业新质生产力发展

创新起主导作用的新质生产力由新劳动者、新劳动对象、新劳动工具、新基础设施等四大要素共同构成&#xff0c;符合新发展理念的先进生产力质态&#xff1b;具有高科技、高能效、高质量等三大突出特征。而通过壮大新产业、打造新模式、激发新动能&#xff0c;新质生产力能够摆脱…...

FastGpt流程

1.知识库 引入文本——>数据清洗 最好将pdf/ppt/xx转换成文本&#xff0c;在文本里面进行数据清洗&#xff08;以防知识库删除后&#xff0c;数据清洗失效&#xff09; 可以插图&#xff0c;将图片通过网页检查F12查看路径放进去 或者直接在csdn放&#xff0c;直接复制链接…...

怎么在UE游戏中加入原生振动效果

我是做振动触感的。人类的五感“视听嗅味触”&#xff0c;其中的“触”就是触觉&#xff0c;是指皮肤、毛发与物体接触时的感觉。触感可以带来更加逼真的沉浸式体验。但也许过于司空见惯&#xff0c;也是习以为常&#xff0c;很多人漠视了触感的价值。大家对触感的认知还远远不…...

【Hadoop技术框架-MapReduce和Yarn的详细描述和部署】

前言&#xff1a; &#x1f49e;&#x1f49e;大家好&#xff0c;我是书生♡&#xff0c;今天的内容主要是Hadoop的后两个组件&#xff1a;MapReduce和yarn的相关内容。同时还有Hadoop的完整流程。希望对大家有所帮助。感谢大家关注点赞。 &#x1f49e;&#x1f49e;前路漫漫&…...

蓝桥杯刷题 前缀和与差分-[3507]异或和之和(C++)

题目描述 给定一个数组 Ai&#xff0c;分别求其每个子段的异或和&#xff0c;并求出它们的和。 或者说&#xff0c;对于每组满足 1≤L≤R≤n 的 L&#xff0c;R求出数组中第 L 至第 R 个元素的异或和。 然后输出每组 L&#xff0c;R 得到的结果加起来的值。 输入格式 输入…...

background背景图参数边渐变CSS中创建背景图像的渐变效果

效果:可以看到灰色边边很难受,希望和背景融为一体 原理: 可以使用线性渐变&#xff08;linear-gradient&#xff09;或径向渐变&#xff08;radial-gradient&#xff09;。以下是一个使用线性渐变作为背景图像 代码: background: linear-gradient(to top, rgba(255,255,255,0)…...

『大模型笔记』吴恩达:AI 智能体工作流引领人工智能新趋势

吴恩达:AI 智能体工作流引领人工智能新趋势 文章目录 一. 概述二. AI 智能体的设计模式2.1. 反思(Reflection)2.2. 使用工具(Tool use)2.3. 规划(Planning)2.4. 多智能体协作(Multi-agent collaboration)三. 最后总结四. 参考文献一. 概述 我期待与大家分享我在 AI 智能体方面…...

腾讯光子工作室群 一面 (30min)

问题&#xff1a; 你毕业是打算考研还是直接工作 深挖项目&#xff08;介绍、剖析遇到问题如何解决&#xff09;&#xff1a; 你在进行攻击的时候会不会有穿模的情况&#xff0c;怎么解决 为什么会造成卡顿&#xff08;多嘴说的&#xff09; 说说行为树和状态机之间的差别 …...

Linux的信号栈的实现(1)

作者 pengdonglin137@163.com 环境 Linux 6.5 + ARM64 概述 在前一篇文章中介绍了Linux系统中的几种栈以及它们之间的切换,进程在用户态和内核态会使用不同的栈,在用户态的主线程和其他线程都有各自的栈,此外进程在执行信号处理程序时也需要栈,那么这个栈来自哪呢? …...

Python学习笔记——heapq

堆排序 思路 堆排序思路是&#xff1a; 将数组以二叉树的形式分析&#xff0c;令根节点索引值为0&#xff0c;索引值为index的节点&#xff0c;子节点索引值分别为index*21、index*22&#xff1b;对二叉树进行维护&#xff0c;使得每个非叶子节点的值&#xff0c;都大于或者…...

搜索与图论——拓扑排序

有向图的拓扑排序就是图的宽度优先遍历的一个应用 有向无环图一定存在拓扑序列&#xff08;有向无环图又被称为拓扑图&#xff09;&#xff0c;有向有环图一定不存在拓扑序列。无向图没有拓扑序列。 拓扑序列&#xff1a;将一个图排成拓扑序后&#xff0c;所有的边都是从前指…...

wordpress设置菜单跳转到锚/安徽360优化

最近有朋友问小编win10系统提示你没有权限在此位置中保存文件怎么办&#xff0c;相信很多人都遇到过这种情况&#xff0c;有时我们在把文件保存到c盘中时会遇到错误提示&#xff1a;“你没有权限在此位置中保存文件。请与管理员联系以获得权限&#xff0c;你想改为保存到Admini…...

短视频网站开发教程/上海网络营销有限公司

要想启动一个应用程序&#xff0c;首先要保证这个应用程序所需要的应用程序进程已经启动。AMS在启动应用程序时会检查这个应用程序需要的应用程序进程是否存在&#xff0c;不存在就会请求Zygote进程启动需要的应用程序进程。下面来看下启动应用进程的大致流程吧&#xff1a; 一…...

网站上线前准备方案/百度商品推广平台

课程设计项目名称&#xff1a;基于flask的可视化动漫分析网站&#xff0c;如果你在学习Python的过程中&#xff0c;往往因为没有好的教程或者没人指导从而导致自己容易放弃&#xff0c;为此我建了个Python交流.裙 &#xff1a;一久武其而而流一思(数字的谐音)转换下可以找到了&…...

爱站网怎么使用/知乎推广公司

1 状态共享 随着组件的细化&#xff0c;就会遇到多组件状态共享的情况&#xff0c;Vuex当然可以解决这类问题&#xff0c;不过就像Vuex官方文档所说的&#xff0c;如果应用不够大&#xff0c;为避免代码繁琐冗余&#xff0c;最好不要使用它&#xff0c;今天我们介绍的是vue.js …...

公司让做网站违法/有免费做网站的吗

Roto 笔刷工具 Roto Brush Tool调整边缘工具 Refine Edge Tool快捷键&#xff1a;Alt WRoto&#xff0c;是 rotoscope 简称&#xff0c;中文意思是“逐格贴合的重覆动画动作”。Roto 笔刷工具有点类似于 Ps 的快速选择工具&#xff0c;可自动判断对象边缘。调整边缘工具类似于…...

苹果网站开发/巨量引擎广告投放

今天弄这个selector把脑壳弄得清痛&#xff0c;最终我的理解如下:官方关于这个的介绍在:http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList先复制一个样例:<?xml version"1.0" encoding"utf-8"?><selecto…...