JVM之class文件结构剖析

news2024/11/30 12:39:42

文章目录

  • 0.前言
  • 1. 引言
    • 1.1 Java编译原理基础
    • 1.2 Class文件在Java编译过程中的角色
  • 2. Class文件的整体结构
    • 2.1 Class 文件组成
  • 3. Class文件的详细解析
    • 3.1 魔数与版本号的作用和意义
    • 3.2 常量池的结构和作用
    • 3.3 访问标志的含义和可能的值
    • 3.4 类索引、父类索引和接口索引集合的作用和构成
    • 3.5 字段表和方法表
    • 3.6 属性表的详细解析
  • 4. Class文件在JVM中的角色
    • 4.1 Class文件在JVM中的生命周期
    • 4.2 JVM是如何加载和使用Class文件的
    • 4.3 Class文件在动态链接、加载和运行机制中的作用
  • 5. javap 命令详解
  • 6. 十六进制编辑器 010 Editor 查看Class 文件
  • 7. 使用jclasslib 工具查看字节码
  • 8.参考文档

0.前言

在Java编译过程中,源代码首先会被编译器编译成为字节码文件,这些文件的后缀名为.class。然而,尽管.class文件在Java编程中占有重要地位,但是大多数Java开发者对其内部的结构和工作原理并不是非常了解。所以抽时间我整理一下,和大家一起学习进步。

本文旨在对Java的.class文件结构进行详细的剖析,让我们一起了解其内部的工作机制。希望大家在阅读本文后, 对Java虚拟机有更多的了解,并在日后的编程工作中更加得心应手。

1. 引言

在了解JVM Class文件结构剖析之前,我们需要对两个基础知识进行了解一下。java 编译原理Class文件在Java编译过程中的角色

1.1 Java编译原理基础

在这里插入图片描述
在Java编译过程中,对于每个阶段的示例如下:

  1. 词法分析
    词法分析:这个阶段会将源代码分割成一系列的词元(Token)。每个词元都是源代码中的一个最小有意义的独立部分,例如关键字(如public, class等)、标识符、运算符等。
    源代码:
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

词法分析后,会得到一系列的词元(Token),如:public, class, HelloWorld, {, public, static, void, main, (, String, [, ], args, ), {, System, ., out, ., println, (, "Hello, World!", ), ;, }, }

  1. 语法分析
    语法分析:语法分析阶段会根据词元,构建出抽象语法树(Abstract Syntax Tree, AST)。AST是一种用于表示程序结构的树形结构,树的每个节点都代表程序代码中的一个构造(例如声明,表达式等)。

语法分析阶段生成的抽象语法树(AST)涵盖源代码的结构信息。以下是HelloWorld类的简化版AST:

  ClassDeclaration
  ├── Modifier: public
  ├── Name: HelloWorld
  └── MethodDeclaration
      ├── Modifier: public
      ├── Modifier: static
      ├── ReturnType: void
      ├── Name: main
      ├── Parameter: String[] args
      └── Block
          └── MethodInvocation
              ├── Name: System.out.println
              └── Argument: "Hello, World!"
  1. 语义分析
    语义分析:这个阶段会检查源代码的语义是否正确。例如类型检查,确保赋值和操作符等的类型正确性。此外,语义分析还包括符号解析,将代码中的变量和类型名称解析为内部的符号引用。

举一例错误的赋值语句:

public class Test {
    public static void main(String[] args) {
        int a = "hello";
    }
}

在语义分析阶段,编译器会检查变量类型是否正确。在这个例子中,尝试将字符串"hello"赋值给整型变量a,这是错误的,编译器会提示类型不匹配的错误。

  1. 代码生成
    代码生成:在所有分析完成后,编译器会生成字节码,字节码是一种中间代码,可以在Java虚拟机(JVM)上执行。

在代码生成阶段,编译器会将以上的源代码转化为以下的Java字节码:

public class HelloWorld {
  public HelloWorld();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #3                  // String Hello, World!
       5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

这是.class文件的内容,可以通过javap -c HelloWorld命令查看。

1.2 Class文件在Java编译过程中的角色

  1. 字节码的载体

    Class文件包含了Java程序的字节码,也就是Java源代码编译之后的结果。Java编译器(如javac)会将Java源代码转化为字节码,字节码是一种中间语言,它比源代码更接近于机器语言。字节码的存在使得Java程序可以在任何安装了Java虚拟机的平台上运行,因为Java虚拟机能够解释和执行字节码。

  2. 实现跨平台特性

    字节码是一种平台无关的中间表示形式,它不依赖于特定的硬件和操作系统。这意味着只要一个设备安装了Java虚拟机,那么这个设备就能够执行Java程序,无论这个设备使用的是什么操作系统。这就是Java的"一次编写,到处运行"的理念。

  3. 动态加载和链接

    Java虚拟机在运行时会动态地加载Class文件。也就是说,Java虚拟机并不会一次性加载所有的Class文件,而是在程序运行过程中,当需要使用到某个类时,才会将这个类的Class文件加载进内存。这种动态加载的机制提高了内存的使用效率。

    除了加载,Java虚拟机还会进行链接。链接是指将Class文件中的符号引用替换为直接引用的过程。符号引用是一种抽象的引用,它可以是任何形式的字符集,用来描述被引用的信息。直接引用则是指向目标的指针、相对偏移量或者是一个能够直接定位到目标的句柄。

  4. 存储元数据

    Class文件中包含了Java类或接口的元数据信息。这些信息包括类名,方法名,字段名以及它们的访问修饰符等。这些元数据在运行时可以被Java虚拟机用于反射、泛型等操作。

    反射的操作包括获取Class实例,获取类的构造方法,字段和方法,创建类的实例,调用方法,访问字段等。

    泛型则是Java语言提供的一种代码抽象和复用机制。Java的泛型是在编译器这个层次来实现的,也就是说,Java的泛型仅仅是给编译器Java源码用的,确保数据的类型安全。而字节码文件中,是不包含泛型中的类型信息的。在编译器编译Java源码到字节码时,会将源码中的泛型擦除,而在需要的地方插入类型强制转换的代码来确保类型正确。

2. Class文件的整体结构

参考Oracle 官方文档 Chapter 4. The class File Format https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html
在这里插入图片描述

2.1 Class 文件组成

部分名称描述
魔数魔数是Class文件的头四个字节,它的唯一作用是确定这个文件是否为一个能被虚拟机接受的Class文件。Java的魔数固定为0xCAFEBABE
版本号版本号是Class文件的次要版本号和主要版本号,它们都占用两个字节。主要版本号确定了Class文件的版本,比如JDK 1.1的主要版本号为45,而JDK 1.2~1.8的主要版本号则分别为46~52。
常量池常量池是Class结构的一部分,它用于存放编译期生成的各种字面量和符号引用。这部分内容将在类加载后进入方法区中。
访问标志访问标志用于识别一些类或接口层次的访问信息,包括:是否为public,是否为abstract,是否为interface等。
类索引、父类索引类索引和父类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名。
接口索引集合接口索引集合用于描述这个类实现了哪些接口,这些接口将被初始化到一个列表中。
字段表字段表用于描述接口或类中声明的变量,变量包括类级别的类变量,还有就是实例变量,没有方法体中的局部变量。
方法表方法表用于描述类或接口中声明的方法。
属性表属性表用于描述某个类,方法和字段的附加信息。比如,可以设置一个字段是否被废弃(Deprecated);还可以设置方法的字节码等。

每个部分都承担着其自身的职责,真正让Java有"一次编写,到处运行"特性的就是字节码,字节码是存储在方法表的code属性里的。

以下是一个简单的Java程序示例,我们将逐步解析其生成的Class文件各部分:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

编译上述Java程序会得到一个HelloWorld.class文件,这个文件包含了字节码和其它相关信息。我们使用JDK自带的javap工具来解析这个Class文件:

javap -verbose HelloWorld

以下是解析结果的一部分:

Classfile /C:/HelloWorld.class
  Last modified Mar 11, 2021; size 434 bytes
  MD5 checksum 63bf0338975b5720bf154f48d8a5db14
public class HelloWorld
  minor version: 0
  major version: 59
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #7                          // HelloWorld
  super_class: #2                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
   #1 = Methodref          #2.#3          // java/lang/Object."<init>":()V
   #2 = Class              #4             // java/lang/Object
   #3 = NameAndType        #5:#6          // "<init>":()V
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Class              #8             // HelloWorld
   #8 = Utf8               HelloWorld
   #9 = Utf8               Code
  #10 = Methodref          #11.#12        // java/lang/System.out:Ljava/io/PrintStream;
  #11 = Class              #13            // java/lang/System
  #12 = NameAndType        #14:#15        // out:Ljava/io/PrintStream;
  #13 = Utf8               java/lang/System
  #14 = Utf8               out
  #15 = Utf8               Ljava/io/PrintStream;
  #16 = String             #17            // Hello, World!
  #17 = Utf8               Hello, World!
  #18 = Methodref          #19.#20        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #19 = Class              #21            // java/io/PrintStream
  #20 = NameAndType        #22:#23        // println:(Ljava/lang/String;)V
  #21 = Utf8               java/io/PrintStream
  #22 = Utf8               println
  #23 = Utf8               (Ljava/lang/String;)V
  #24 = Utf8               main
  #25 = Utf8               ([Ljava/lang/String;)V
  #26 = Utf8               SourceFile
  #27 = Utf8               HelloWorld.java
  #28 = Utf8               LineNumberTable
  #29 = Utf8               LocalVariableTable
  #30 = Utf8               this
  #31 = Utf8               LHelloWorld;
  #32 = Utf8               args
  #33 = Utf8               [Ljava/lang/String;
{
  public HelloWorld();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LHelloWorld;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang.String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #16                 // String Hello, World!
         5: invokevirtual #18                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 3: 0
        line 4: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  args   [Ljava/lang/String;
}
SourceFile: "HelloWorld.java"

从中我们可以看到:

  • 魔数、版本号:javap工具并未直接显示,但我们知道每个Class文件的开头四个字节就是魔数,而紧接着的4个字节代表版本号。

  • 常量池:在"Constant pool"部分,包含了本程序中所使用到的各种常量和符号引用。

  • 访问标志:在"flags"部分显示,ACC_PUBLIC表示这是一个public类,ACC_SUPER是Java编译器为了支持某些编译优化而设定的。

  • 在这里插入图片描述

  • 类索引、父类索引:在"this_class"和"super_class"部分显示,分别表示这个类自身和其父类在常量池中的索引。

  • 接口索引集合:本例没有实现任何接口,所以此部分为空。

  • 字段表:本例没有定义任何字段,所以此部分为空。

  • 方法表:在"Code"部分可以看到两个方法的字节码,一个是默认的构造函数<init>,一个是我们定义的main方法。

  • 属性表:在"SourceFile"部分显示,表示这个Class文件对应的源文件名。

3. Class文件的详细解析

在这里插入图片描述

3.1 魔数与版本号的作用和意义

魔数(Magic Number)是用来标识文件格式的一种约定,Java Class文件的魔数是0xCAFEBABE。当Java虚拟机加载Class文件时,首先会检查这个魔数,如果不是0xCAFEBABE,那么JVM会拒绝加载这个文件。

版本号(Version Number)包括主版本号和次版本号,主版本号变化通常代表JVM做了不兼容的修改,次版本号变化则表示JVM做了向后兼容的修改。JVM在加载Class文件时,也会检查版本号,如果文件的版本高于JVM的版本,那么JVM会拒绝加载这个文件。

3.2 常量池的结构和作用

常量池(Constant Pool)是Java Class文件结构的一个重要部分,它主要存储两类常量:字面量(Literal)和符号引用(Symbolic Reference)。字面量包括文本字符串、声明为final的常量值等;符号引用则包括类和接口的全限定名、字段的名称和描述符、方法的名称和描述符等。

常量池的主要作用是为Java Class文件中的字面量和符号引用提供统一的存储空间,当Java虚拟机执行Class文件中的字节码时,会使用到常量池中的数据。

3.3 访问标志的含义和可能的值

访问标志(Access Flags)用于标识类或接口的访问权限和特性。如public(0x0001)、final(0x0010)、super(0x0020)、interface(0x0200)、abstract(0x0400)等。

3.4 类索引、父类索引和接口索引集合的作用和构成

类索引、父类索引和接口索引集合用于确定类的继承关系。类索引代表当前类,父类索引代表当前类的直接父类,接口索引集合代表当前类实现的所有接口。

3.5 字段表和方法表

字段表(Field Table)用于描述类或接口中声明的变量,包括字段的名称、描述符、访问标志等信息。方法表(Method Table)用于描述类或接口中声明的方法,包括方法的名称、描述符、访问标志、字节码等信息。

3.6 属性表的详细解析

属性表(Attribute Table)用于描述类、字段和方法的附加信息,例如源文件名(SourceFile)、字段的常量值(ConstantValue)、方法的字节码(Code)、已废弃信息(Deprecated)等。不同的属性有不同的内部结构,但都遵循“属性名索引-属性长度-属性信息”这样的基本格式。

4. Class文件在JVM中的角色

4.1 Class文件在JVM中的生命周期

Java虚拟机(JVM)对Class文件的处理可以分为以下几个阶段:

  1. 加载(Loading): 在这个阶段,JVM从本地磁盘、网络或者其他来源加载.class文件。加载完成之后,JVM将会创建一个表示这个类的java.lang.Class对象。

  2. 验证(Verification): 为了确保Class文件的正确性,JVM会对加载进来的字节码文件进行严格的验证,包括文件格式验证、元数据验证、字节码验证、符号引用验证等。如果验证失败,JVM将抛出java.lang.VerifyError异常。

  3. 准备(Preparation): 在这个阶段,JVM会为类变量(static变量)分配内存,并设置类变量的初始值。同时,JVM还会为类的方法表、接口表等分配内存。

  4. 解析(Resolution): 这个阶段主要执行符号引用到直接引用的转换。JVM将会解析类中的方法、字段、类、接口等的符号引用,将其替换为直接引用。

  5. 初始化(Initialization): 初始化阶段主要执行类构造器<clinit>方法,以及静态变量的赋值操作。这个阶段会确保类的初始化过程是线程安全的。

  6. 使用(Using): 类成功加载、验证、解析和初始化之后,就可以被程序使用了。这时,程序可以创建类的实例、调用方法、访问字段等。

  7. 卸载(Unloading): 当类不再被引用,并且在垃圾收集器运行后被标记为可回收时,JVM会卸载这个类。此时,JVM会释放与类相关的所有内存资源。

4.2 JVM是如何加载和使用Class文件的

JVM使用类加载器(ClassLoader)来加载和管理Class文件。类加载器负责将Class文件的字节码加载到内存中,并且执行验证、准备、解析等操作。在这个过程中,类加载器还会处理类之间的依赖关系,保证类的正确加载。

当程序需要使用一个类时,类加载器会首先查找是否已经加载过这个类。如果没有加载过,类加载器会根据类的全限定名(包名+类名)加载类的字节码,然后执行整个生命周期的操作。

一旦类被加载到JVM中,它就可以被程序使用。程序可以通过创建类的实例、调用方法、访问字段等方式使用这个类。

4.3 Class文件在动态链接、加载和运行机制中的作用

Class文件是Java程序在JVM中的载体。它包含了类的所有信息,包括类的属性、方法、常量池等。在Java程序执行的过程中,JVM通过动态链接、加载和运行机制来管理和使用Class文件。

  • 动态链接:JVM在运行时将符号引用替换为直接引用的过程称为动态链接。Class文件中的符号引用包括方法引用、字段引用、类引用等。动态链接保证了Java代码可以在不同的环境下运行。

  • 加载:JVM通过类加载器将Class文件加载到内存中。在这个过程中,JVM会执行验证、准备、解析等操作,确保类的正确性和可用性。

  • 运行:加载完成的Class文件可以被程序使用。在运行期间,JVM会执行类的方法、访问字段、创建实例等操作。同时,JVM还会处理异常、垃圾回收等任务,保证程序的正常运行。

5. javap 命令详解

在上面的示例介绍中我们使用了一个命令

javap -verbose HelloWorld

那么我单独拉出来,给大家聊一下这个命令的作用。

javap 是Java虚拟机自带的反编译工具,用于从命令行解析class文件,打印出字节码、常量、构造方法、函数等等的信息。以下是javap命令的一些常用选项:

  • -help:查看帮助文档
  • -version:输出javap的版本信息
  • -v-verbose:详细输出,输出额外的更为详细的信息,比如常量池信息、版本信息、字节码指令等
  • -l:输出行号和本地变量表
  • -public:只显示public的类和成员
  • -protected:只显示protected的类和成员
  • -package:只显示package的类和成员
  • -private:显示所有的类和成员
  • -c:对代码进行反汇编
  • -s:输出内部类型签名
  • -sysinfo:用于输出系统信息,包括主版本号、次版本号等
  • -constants:显示最终常量

也可以混合使用多个选项,如javap -private -c HelloWorld可以显示HelloWorld中所有的类和成员,以及反汇编出的字节码。

假设我们有以下的一个简单的Java类HelloWorld.java

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

首先,我们需要使用javac命令编译这个Java文件,生成对应的Class文件:

javac HelloWorld.java

然后,我们就可以使用javap命令查看生成的Class文件的内容了。我们先只查看Class文件的概述:

javap HelloWorld

输出如下:

Compiled from "HelloWorld.java"
public class HelloWorld {
  public HelloWorld();
  public static void main(java.lang.String[]);
}

这里我们可以看到,javap默认输出了Class文件的类名,以及其中的方法。

接下来,我们使用 -v 参数打印Class文件的详细内容:

javap -v HelloWorld

输出如下:

Classfile /path/to/HelloWorld.class
  Last modified Apr 15, 2021; size 455 bytes
  MD5 checksum 9d422a48a6a88f5c6ed5d6eb7cce5015
  Compiled from "HelloWorld.java"
public class HelloWorld
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#10         // java/lang/Object."<init>":()V
   #2 = Fieldref           #11.#12        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #13            // Hello, world!
   #4 = Class              #14            // java/lang/Object
   #5 = Class              #15            // HelloWorld
   #6 = Methodref          #16.#17        // java/io/PrintStream.println:(Ljava/lang/String;)V
  ...
  ...

这个输出包含了HelloWorld Class文件的很多详细信息,如版本号、访问标志、常量池等等。例如,我们可以在常量池中看到Hello, world!这个字符串常量。

6. 十六进制编辑器 010 Editor 查看Class 文件

参考 https://bbs.kanxue.com/thread-257797.htm
参考 https://blog.csdn.net/freeking101/article/details/102908538

在这里插入图片描述
以下是您可以手动应用模板的方法,以防文件扩展名不是原始扩展名

在这里插入图片描述
这是模板结果的样子:

在这里插入图片描述
在十六进制/ASCII转储下方,显示了模板结果:一组嵌套字段,与.class文件的内部结构相匹配。例如,我在这里选择的第一个字段是u4 magic,它是一个.class文件的魔数标头:CAFEBABE。
在这里插入图片描述

7. 使用jclasslib 工具查看字节码

jclasslib 是一个功能丰富的字节码查看器,用于查看和分析 Java class 文件的结构。

  1. 下载和安装 jclasslib

官网 https://jclasslib.org/ 免费开源

  1. 打开 jclasslib

    安装完成后,打开 jclasslib。会看到一个简洁的界面。
    在这里插入图片描述
    在这里插入图片描述

  2. 打开 class 文件

    点击菜单栏的 File > Open... 选项,浏览的文件系统找到要查看的 .class 文件,选择它然后点击 Open

    或者,也可以直接把 .class 文件拖拽到 jclasslib 的窗口中。
    在这里插入图片描述

  3. 查看字节码

    成功打开 .class 文件后,会在左侧看到一个树形结构,表示了 .class 文件的结构。可以点击树形结构的各个节点查看详细的信息。

    右侧的窗口会根据选中的节点显示对应的详细信息。例如,如果选中了 constant_pool 节点,右侧就会显示常量池的所有内容。

    jclasslib 还提供了一个 Hex viewer 选项卡,可以在这里查看每个节点的原始字节码。

8.参考文档

https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html

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

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

相关文章

如何在小程序中设置页面显示的文字

不同商家&#xff0c;对于小程序有不同的要求。所以&#xff0c;小程序应该支持商家在后台灵活配置小程序各个页面的文字显示。下面具体介绍如何显示各个页面的文字。 朋友圈分享图文字&#xff1a;会显示在朋友圈海报顶部 升级会员提示&#xff1a;对于普通会员&#xff0c;在…

一些基础知识

一些基础知识笔记Git clone gitxxxxx pip install -r requirements.txt -i https://pypi.mirrors.ustc.edu.cn/simple wget google.com 可以快速看你的服务器到底有没有链接代理 benchmark和baseline L1 loss & MSE loss L1是差的绝对值和&#xff0c;MSE是差的平方和 …

KMP 算法 + 详细笔记

给两个字符串&#xff0c;T"AAAAAAAAB"&#xff0c;P"AAAAB"; 可以暴力匹配&#xff0c;但是太费时和效率不太好。于是KMP问世&#xff0c;我们一起来探究一下吧&#xff01;&#xff01;&#xff01; &#xff08;一&#xff09;最长公共前后缀 D[i] p[…

【Vue面试题三十】、vue项目本地开发完成后部署到服务器后报404是什么原因呢?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;vue项目本地开发完成后部…

电脑技巧:PrivaZer电脑清理工具介绍

目录 一、软件介绍 二、功能介绍 三、软件特点 清理和保护 防止恢复 Cookie的智能清理 四、软件下载 今天给大家推荐一款非常实用的电脑垃圾清理工具&#xff0c;感兴趣的朋友可以下载看看&#xff01; 一、软件介绍 PrivaZer是一款免费好用的老牌清理软件&#xff0c;除…

详解Pinia和Vuex

一、vuex介绍 1.什么是vuex&#xff1f;为什么要使用vuex? Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 库。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 在vue最重要的就是数据驱动和组件化&#x…

苍穹外卖(八) 使用WebSocket协议完成来单提醒及客户催单功能

WebSocket介绍 WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信(双向传输)——浏览器和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c; 并进行双向数据传输。 HTTP协议和WebSocket协议对比&#xff1a; HTTP…

排序-算法

文章目录 一、排序的概念及引用1.1 排序概念1.2 排序运用1.3 常见排序算法 二、常见排序算法的实现2.1 插入排序2.1.1 基本思想2.1.2 直接插入排序2.1.3 希尔排序 2.2 选择排序2.2.1 基本思想2.2.2 直接选择排序2.2.3 堆排序 2.3 交换排序2.3.1 冒泡排序2.3.2 快速排序2.3.3 快…

Godot C# 扩展方法持续更新

前言 为了简化Godot 的编写&#xff0c;我会将我的扩展方法写在这里面。 更新日期(2023年10月15日) Nuget 包安装 扩展方法 public static class GD_Extension{/// <summary>/// 假数据生成&#xff0c;详情请看Bogus官方文档/// </summary>public static Faker…

介绍6种解决电脑找不到vcomp140.dll,无法继续执行代码的方法。

在编程和软件开发领域&#xff0c;我们经常会遇到各种错误和问题。其中&#xff0c;找不到vcomp140.dll文件导致无法继续执行代码是一个非常常见的问题。这个问题可能会影响到软件的正常运行&#xff0c;甚至导致整个项目延期。因此&#xff0c;我们需要找到解决方案来解决这个…

pwnable-1-fd

pwn的学习周期确实比较长&#xff0c;需要的前置内容也很多&#xff0c;了解到第一题还算比较简单的&#xff0c;那就先来体验一波~顺带附一波网站链接:&#x1f449;网站链接 题目 WP 最后一行给出了ssh链接方式&#xff0c;那就先连接一波 第一次连接会有第四行的询问&…

怎么团队合作,协作开发

一、代码托管平台 我是在大一下的一个竞赛中接触到的代码托管平台 那个时候我也算是什么都不会的&#xff0c;不过不得不说这个确实比较重要&#xff0c;对我造成了一些冲击 在我看来&#xff0c;代码托管平台的作用就是在一个中转站&#xff08;仓库&#xff09;上存储我们写…

283 移动零

解题思路&#xff1a; \qquad 适用双指针&#xff0c;l&#xff1a;最左边‘0’元素坐标&#xff1b;r&#xff1a;l右边第一个非零元素坐标。 \qquad 最初的思路&#xff1a;将l和r初始化为0&#xff0c;遍历数组nums若任意一个指针到达数组末尾时停止。若当前nums[l] 0则移…

【iOS】计算器仿写

文章目录 前言一、构建View界面二、Model中进行数据处理三、Controller层实现View与Model交互总结 前言 在前两周组内进行了计算器的仿写&#xff0c;计算器仿写主要用到了MVC框架的思想以及数据结构中用栈进行四则运算的思想&#xff0c;还有就是对OC中的字符串进行各种判错操…

Linux系统编程:文件描述符以及IO多路复用

书接上回&#xff0c;我们之前学习的文件系统编程都是在内存空间中的文件流&#xff08;用户态文件缓冲区&#xff09;内进行操作的&#xff0c;比如使用的fopen、fclose、fread和fwrite等等都是库函数&#xff0c;并没有用到内核态的功能&#xff08;实际上库函数中调用的是内…

hive排序

目录 order by (全局排序asc ,desc) sort by(reduce 内排序) Distribute by(分区排序) Cluster By&#xff08;当 distribute by 和 sorts by 字段相同时 &#xff0c;可以使用 &#xff09; order by (全局排序asc ,desc) INSERT OVERWRITE LOCAL DIRECTORY /home/test2 …

Ubuntu系统下配置安装区块链Hyperledger Fabric(新手小白篇)

有些安装过程比较简单的&#xff0c;不会详细赘述。主要还是集中在Hyperledger Fabric的配置上。 本篇主要介绍在Ubuntu系统上安装Hyperledger Fabric的过程。这里使用的Ubuntu&#xff1a;16.04 LTS。 1. Git安装 Git工具安装命令如下&#xff1a; sudo apt update sudo ap…

基于主动移频法与AFD孤岛检测的单相并网逆变器matlab仿真

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 仿真模型 算法介绍 (1)仿真模型由单相电网、逆变器、滤波环节、PI控制器、PWM生成器、锁相环、AFD控制器s函数、测量模块等构成&#xff1b; (2)采用主动移频法(AFD)进行孤岛检测&#xff1b; (3)相应速度…

MATLAB——径向基神经网络预测程序

欢迎关注公众号“电击小子程高兴的MATLAB小屋” %% 学习目标&#xff1a;径向基神经网络 %% 可以以任意精度逼近任意连续函数 clear all; close all; P1:10; T[2.523 2.434 3.356 4.115 5.834 6.967 7.098 8.315 9.387 9.928]; netnewrbe(P,T,2); %建立精确的径向基…

语料库应用入门讲座

语料库应用入门讲座 引言 主要介绍语料库的概念、功能、意义和基础的方法。主要包括&#xff1a; 1. 什么是语料库&#xff1f;语料库有什么作用&#xff1f; 2. 语料库的分类有哪些&#xff1f; 3. 语料库有什么功能&#xff1f; 4. 常见的语料库工具有哪些&#xff1f; …