零基础入门学用Arduino 第五部分

 重要的内容写在前面:

  1. 该系列是以up主太极创客的零基础入门学用Arduino教程为基础制作的学习笔记。
  2. 个人把这个教程学完之后,整体感觉是很好的,如果有条件的可以先学习一些相关课程,学起来会更加轻松,相关课程有数字电路(强烈推荐先学数电,不然可能会有一些地方理解起来很困难)、模拟电路等,然后就是C++(注意C++是必学的)
  3. 文章中的代码都是跟着老师边学边敲的,不过比起老师的版本我还把注释写得详细了些,并且个人认为重要的地方都有详细的分析。
  4. 一些函数的介绍有参考太极创客官网给出的中文翻译,为了便于现查现用,把个人认为重要的部分粘贴了过来并做了一些修改。
  5. 如有错漏欢迎指正。

视频链接:零基础入门学用Arduino-专项教程2(面向对象基础)1 初始面向对象_哔哩哔哩_bilibili

太极创客官网:太极创客 – Arduino, ESP8266物联网的应用、开发和学习资料

一、类和对象基础认识

1、面向对象概述

(1)C++面向对象的三大特性为:封装、继承、多态

(2)C++认为万事万物都皆为对象,对象上有其属性和行为。例如:

①舵机可以作为对象,属性有控制引脚在Arduino上的编号,行为有转动输出轴至某一角度等。

②步进电机也可以作为对象,属性步进模式、输出轴转动一周所需步数、控制引脚在Arduino上的编号等,行为有转动、静止等。

2、封装

        具有相同性质的对象,我们可以抽象称为,例如舵机属于舵机类、步进电机属于步进电机类,设计者需要将类的属性和行为设计出来,使用者根据类创建对象,然后直接使用设计者封装好的属性和行为即可。

3、继承

(1)类的继承是新的类从已有类那里得到已有的特性,从已有的类产生新类的过程就是类的派生。在继承过程中,原有的类或已经存在的用来派生新类的类称为基类或父类,而由已经存在的类派生出的新类则称为派生类或子类

(2)从派生类的角度,根据它所拥有的基类数目不同,可以分为单继承和多继承,一个类只有一个直接基类时称为单继承,一个类同时有多个直接基类时则称为多继承(在实际开发中不建议用多继承)。

(3)基类与派生类之间的关系如下:

基类是对派生类的抽象,派生类是对基类的具体化。基类抽取了它的派生类的公共特征,而派生类通过增加信息将抽象的基类变为某种有用的类型,派生类是基类定义的延续。

②派生类是基类的组合。多继承可以看作是多个单继承的简单组合。

公有派生类的对象可以作为基类的对象处理,这一点与类聚集(类的数据成员中有另一个类)是不同的,在类聚集中,一个类的对象只能拥有作为其成员的其它类的对象,但不能作为其它类对象而使用。

二、类和对象的基本语法

1、类的定义

(1)类的定义可以分为说明部分和实现部分两部分,其中说明部分说明类中包含的数据成员和成员函数,实现部分是对成员函数的定义。

(2)类定义的一般格式如下:

//类的说明部分

class <类名>

{

public:

        <成员函数或数据成员的说明>    //公有成员,外部接口

protected:

        <成员函数或数据成员的说明>    //保护成员

private:

        <成员函数或数据成员的说明>    //私有成员

};    //花括号括住的属于类内范围

//类的实现部分

<各个成员函数的实现>

①class是声明类的关键字,类名是要声明的类的名字,必须符合标识符定义规则。

②花括号表示类的声明范围,其后的分号表示类声明结束。

③类的成员包括数据成员和成员函数,分别描述类所表达的属性和行为。

④关键字public、private和protected称为访问权限修饰符,它们限制了类成员的访问控制范围。

(3)类的数据成员:

类中的数据成员描述类所表达的问题的属性

②数据成员在类体中进行定义,其定义方式与一般变量相同,在定义类的数据成员时需要注意以下几个问题:

[1]对数据成员的访问会受到访问权限修饰符的控制。

[2]类中的数据成员可以是任意类型,包括整型、浮点型、字符型、数组、指针和引用等,也可以是其它类的对象自身类不行,但自身类的指针可以)。

[3]在类体中不允许对所定义的数据成员进行初始化

(4)类的成员函数:

①类的成员函数描述类所表达的问题的行为。

②各个成员函数的实现既可以在类体内定义(在类体内定义的成员函数都是内联函数,类体内定义则不需要对函数进行声明),也可以在类体外定义(类体外定义的话,类体内需要对函数进行声明)。

[1]如果一个成员函数在类体内进行了定义,它将不出现在类的实现部分。如果所有的成员函数都在类体内进行了定义,则可以省略类的实现部分。

[2]如果要将定义在类体外的成员函数也作为内联函数处理,就必须在成员函数的定义前加上关键字inline。

//类的说明部分

class <类名>

{

public:

        <返回类型> <成员函数名>(<参数表>)    //类内实现

        {

                <函数体>

        }

        <返回类型> <成员函数名>(<参数表>);   //类内声明,类外实现

};    //花括号括住的属于类内范围

//类的实现部分

<返回类型> <类名>::<成员函数名>(<参数表>){

        <函数体>

}

③成员函数除了可以定义为内联函数以外,也可以进行重载,还可以对其形参设置默认值。

2、对象的定义

(1)对象是类的实例,一个对象必须属于一个已知的类,因此在定义对象之前,必须先定义该对象所属的类。

(2)对象的定义格式如下:

        <类名> <对象名>(<参数表>);

①类名是待定义的对象所属的类的名字。

②可以有一个或多个对象名,多个对象名之间用逗号分隔。

参数表是初始化对象时需要的,建立对象时可以根据给定的参数调用相应的构造函数对对象进行初始化无参数时表示调用类的默认构造函数

(3)一个对象的成员就是该对象的类所定义的成员,包括数据成员和成员函数。定义了对象后,可以用“.”运算符和“->”运算符访问对象的成员,其中“.”运算符适用于一般对象和引用对象,而“->”运算符适用于指针对象(即指向对象的指针)

<对象名>.<数据成员名>    //通过对象名访问对象的数据成员

<指针名>-><数据成员名>   //通过指向对象的指针访问对象的数据成员

<对象名>.<成员函数名>(<参数表>)    //通过对象名访问对象的成员函数

<指针名>-><成员函数名>(<参数表>)   //通过指向对象的指针访问对象的成员函数

3、构造函数和析构函数

(1)定义一个类对象时,编译程序要为对象分配存储空间,进行必要的初始化,在C++中,这项工作是由构造函数来完成的,构造函数的作用是在对象被创建时利用特定的值构造对象,将对象初始化为一种特定的状态,使该对象具有区别于其它对象的特征。与构造函数对应的是析构函数,当撤销类对象时,析构函数负责回收存储空间,并做一些善后工作。

(2)构造函数也是类的成员函数,但它是一种特殊的成员函数,它除了具有一般成员函数的特性之外,还具有一些特殊的性质:

构造函数的名字必须与类名相同

构造函数不指定返回类型,它隐含有返回值,由系统内部使用。

构造函数可以有一个或多个参数(还可以设置默认参数),因此构造函数可以重载

在创建对象时,系统会自动调用构造函数

(3)析构函数也是类中的一种特殊成员函数,它具有以下一些特性:

析构函数名是在类名前加求反符号“~”

析构函数不指定返回类型,它不能有返回值。

析构函数没有参数,因此析构函数不能重载,一个类中只能定义一个析构函数

在撤销对象时,系统会自动调用析构函数

(4)构造函数和析构函数的定义:

①构造函数的定义(这里只展示类内定义):

class <类名>

{

public:

        <类名>(<参数表>) : <数据成员名>(<表达式>), <数据成员名>(<表达式>), …

        {

                <构造函数体>

        }

        <成员函数或数据成员的说明>

};

[1]冒号后面是一个构造函数的初始化列表,用于初始化类中的各个数据成员。

[2]初始化列表位于构造函数的形参表之后,函数体代码之前,由一个冒号和逗号分隔的若干项构成。

[3]每一个构造函数的初始化列表项都由数据成员标识符和其后的括号表达式构成。

[4]在调用构造函数对类对象初始化时,先执行初始化列表对各个成员进行初始化,再执行构造函数体

[5]初始化列表中各个初始化项的执行顺序取决于类成员在类中声明的顺序,而与初始化列表给出的初始化项的顺序无关。

[6]对于大多数数据成员而言,既可以使用初始化列表的方式获得显式初值,也可以在获得默认初值后再在构造函数体中使用赋值语句将表达式的值赋值给数据成员

[7]当一个类的成员是另外一个类的对象时,该对象就称为成员对象,当类中出现了成员对象时,该类的构造函数要包含成员对象的初始化。

②析构函数的定义:

class <类名>

{

public:

        ~<类名>( )

        {

                <析构函数体>

        }

        <成员函数或数据成员的说明>

};

(5)默认构造函数和默认析构函数:

构造和析构都是必须有的实现,否则编译器会自己提供空实现

②构造函数的空实现:

class <类名>

{

public:

        <类名>( ) {

        }

};

③析构函数的空实现:

class <类名>

{

public:

        ~<类名>( ) {

        }

};

4、拷贝构造函数

(1)类中有一种特殊的构造函数叫做拷贝构造函数(也叫复制构造函数),它用一个已知的对象初始化一个正在创建的同类对象。

(2)拷贝构造函数的一般格式如下(这里仅给出类内定义的构造函数):

class <类名>

{

public:

        <类名>(const <类名>& <引用对象名>){

                <拷贝构造函数体>

        }

        <成员函数或数据成员的说明>

};

(3)拷贝构造函数具有以下特点:

①拷贝构造函数也是一种构造函数,因此函数名与类名相同,并且不能指定函数返回类型。

②只有一个参数,是对同类的某个对象的引用。

每一个类中都必须有一个拷贝构造函数,如果类中没有定义拷贝构造函数,编译器会自动生成一个具有上述形式的公有拷贝构造函数

(4)拷贝构造函数在以下三种情况下会被调用:

用类的一个已知的对象去初始化该类的另一个正在创建的对象

采用值传递调用方式时,对象作为函数实参传递给函数形参

对象作为函数返回值

5、构造函数的分类及调用

(1)根据参数列表是否为空可将构造函数分为有参构造和无参构造,根据参数类型可将构造函数分为普通构造和拷贝构造。

(2)调用构造函数的三种方式:括号法、显示法、隐式转换法。

class Unknown_hardware
{
public:
  Unknown_hardware(){  //构造函数
    //Unknown_hardware无参构造函数的调用
  }
  Unknown_hardware(int a){  //构造函数
    pin = a;
    //Unknown_hardware有参构造函数的调用
  }
  Unknown_hardware(const Unknown_hardware &p){  //拷贝构造函数
    pin = p.pin;   //将传入的对象身上的所有属性拷贝到这里
    //Unknown_hardware拷贝构造函数的调用
  }
  ~Unknown_hardware(){  //析构函数
    //Unknown_hardware析构函数的调用
  }
  int pin;
};
void setup()
{
  //无内容
}

void loop() 
{
  //括号法(推荐)
  Unknown_hardware p1;     //默认构造函数调用(千万不要加小括号,否则编译器会认为是函数声明)
  Unknown_hardware p2(10); //有参构造函数调用
  Unknown_hardware p3(p2); //拷贝构造函数调用

  //显示法
  Unknown_hardware p4;               //默认构造函数调用
  Unknown_hardware p5 = Unknown_hardware(10);  //有参构造函数调用
  Unknown_hardware p6 = Unknown_hardware(p5);  //拷贝构造函数调用(不要利用拷贝函数初始化匿名对象,即Unknown_hardware(p5);)
  Unknown_hardware(10);  //匿名对象,创建了一个没名字的对象,当前行执行结束后系统会立即回收它
  
  //隐式转换法
  Unknown_hardware p7 = 10;   //相当于Unknown_hardware p7 = Unknown_hardware(10);
  Unknown_hardware p8 = p7;   //相当于Unknown_hardware p2 = Unknown_hardware(p7);
}

(3)默认情况下,C++编译器至少会给一个类添加3个函数,分别为默认构造函数(无参,函数体为空)、默认析构函数(无参,函数体为空)、默认拷贝构造函数。

如果用户定义有参构造函数,C++不再提供默认无参构造,但是会提供默认拷贝构造

如果用户定义有拷贝构造函数,C++不会再提供其它构造函数

(4)类对象作为类成员,定义类对象时,先调用类成员的构造函数,再调用类对象的构造函数;销毁类对象时,先调用类对象的析构函数,再调用类成员的析构函数。(类中有多个成员对象时,成员对象构造函数的执行顺序仅与成员对象在类中声明的顺序有关,而与成员初始化列表中给出的成员对象的顺序无关)

三、使用类和对象的思想点灯

1、点灯电路连接

2、示例程序1——蓝色LED闪烁3次

class Led {     //LED灯类
  public:
    Led();       //构造函数声明
    ~Led();      //析构函数声明
    void on();  //点灯操作函数声明
    void off(); //闭灯操作函数声明
};
 
Led::Led(){
  Serial.println("Led Object Created.");
  pinMode(2, OUTPUT);  //初始化2号引脚为输出模式
}
Led::~Led(){
  Serial.println("Led Object Deleted.");
}
void Led::on(){
  digitalWrite(2, HIGH);  //蓝色LED被点亮
}
void Led::off(){
  digitalWrite(2, LOW);  //蓝色LED被熄灭
}
 
void setup() 
{
  Serial.begin(9600);
  Led myLed;   //根据led类创建LED对象
  Serial.println("Hello, this is from Setup()");
  for(int i = 0; i < 3; i++)
  {
    myLed.on();   //myLed做点灯行为
    delay(1000);
    myLed.off();  //myLed做闭灯行为
    delay(1000);
  }
}
 
void loop() 
{
 //无内容
}

3、示例程序2——两个LED闪烁3次

class Led {         //LED灯类
  public:
    Led();                 //无参构造函数声明
    Led(int userLedPin);   //有参构造函数声明
    ~Led();                //析构函数声明
    void on();
    void off();
    int ledPin = 2;        //属性——LED连接引脚2
};

Led::Led(){
  Serial.println("Led Object Created.");
  pinMode(2, OUTPUT);          //初始化引脚2为输出模式
}
Led::Led(int userLedPin) {
  Serial.println("Led Object Created.");
  ledPin = userLedPin;         //更改LED连接的引脚号为userLedPin
  pinMode(ledPin, OUTPUT);     //初始化userLedPin引脚为输出模式
}
Led::~Led(){
  Serial.println("Led Object Deleted.");
}
void Led::on(){
  digitalWrite(ledPin, HIGH);  //点亮引脚ledPin连接的LED
}
void Led::off(){
  digitalWrite(ledPin, LOW);  //熄灭引脚ledPin连接的LED
}

void setup() 
{
  Serial.begin(9600);
  Led myLed;      //蓝色LED连接引脚2
  Led myLed2(7);  //绿色LED连接引脚7
  Serial.println("Hello, this is from Setup()");
  for(int i = 0; i < 3; i++){
    myLed.on();   //蓝色LED点灯
    myLed2.on();  //绿色LED点灯
    delay(1000);
    myLed.off();  //蓝色LED闭灯
    myLed2.off(); //绿色LED闭灯
    delay(1000);
  }
}

四、程序的分文件编写

1、分文件编写的目的与步骤

(1)分文件编写的目的:在实际开发中,代码量往往不止几十行,为了便于管理和检查错

误,通常需要将不同功能的代码写在不同的文件中。

(2)分文件编写的步骤:

①在项目文件夹中创建.h格式以及.cpp格式的文件。

②将函数的实现以及类的实现写在其它源文件(也就是.cpp文件)中。

③将函数的声明写在与其源文件同名的头文件(也就是.h文件)中,使用“#include”预处理指令将函数实现需要包含的头文件添加在该头文件中,另外不管头文件的情况如何,都要包含Arduino.h文件。

④在函数实现所在的源文件中使用“#include”预处理指令将函数声明所在的头文件添加进

来。

⑤需要调用函数的文件中使用“#include”预处理指令将函数声明所在的头文件添加进来即

可。

2、示例项目(由上例改编)

(1)项目文件夹结构:(分文件不一定要与项目文件夹的名称相同)

(2)Led.ino文件:

#include "Led.h"

void setup() 
{
  Serial.begin(9600);
  Led myLed;      //蓝色LED连接引脚2
  Led myLed2(7);  //绿色LED连接引脚7
  Serial.println("Hello, this is from Setup()");
  for(int i = 0; i < 3; i++){
    myLed.on();   //蓝色LED点灯
    myLed2.on();  //绿色LED点灯
    delay(1000);
    myLed.off();  //蓝色LED闭灯
    myLed2.off(); //绿色LED闭灯
    delay(1000);
  }
}

void loop() 
{
  //无内容
}

(3)Led.h文件:

#ifndef _LED_H_
#define _LED_H_

#include <Arduino.h>

class Led {         //LED灯类
  public:
    Led();                 //无参构造函数声明
    Led(int userLedPin);   //有参构造函数声明
    ~Led();                //析构函数声明
    void on();
    void off();
    int ledPin = 2;        //属性——LED连接引脚2
};

#endif

(4)Led.c(Led.cpp)文件:

#include "Led.h"

Led::Led(){
  Serial.println("Led Object Created.");
  pinMode(2, OUTPUT);          //初始化引脚2为输出模式
}
Led::Led(int userLedPin) {
  Serial.println("Led Object Created.");
  ledPin = userLedPin;         //更改LED连接的引脚号为userLedPin
  pinMode(ledPin, OUTPUT);     //初始化userLedPin引脚为输出模式
}
Led::~Led(){
  Serial.println("Led Object Deleted.");
}
void Led::on(){
  digitalWrite(ledPin, HIGH);  //点亮引脚ledPin连接的LED
}
void Led::off(){
  digitalWrite(ledPin, LOW);  //熄灭引脚ledPin连接的LED
}

五、自建Arduino库

        继续以上例做延伸,在.ino文件上一级的Arduino文件夹中有一个libraries文件夹,这个文件夹用于存放第三方库,打开这个文件夹,在其中建立新文件夹Led,然后把上例中的Led.h文件和Led.c(Led.cpp)移动至该文件夹中,即完成第三方库的创建,程序可以直接使用之。

​​​​​​​

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

有效粉丝不够怎么办,巨量千川助你快速涨粉,解锁更多权限

在当今的社交媒体时代&#xff0c;拥有大量的粉丝对于个人或品牌的发展至关重要。除此之外开通权限也受粉丝数量的限制&#xff08;开通橱窗带货被要求500有效粉丝&#xff0c;开蓝V也需要500粉丝&#xff0c;直播权限需要1000粉丝&#xff09;。那么怎样才能快速涨粉又对账号没…

PS系统教程23

减淡加深海绵工具 减淡工具 作用&#xff1a;提炼物体颜色 加深工具 作用&#xff1a;变暗物体颜色&#xff0c;加深物体深度 海绵工具 作用&#xff1a;修正物体饱和度&#xff0c;加大纯度 减淡工具 老套路&#xff0c;找一个图片 复制新建粘贴Ctrl键J复制图层选择减…

C语言学习之路(黑马)

文章目录 环境搭建HelloWorld代码编写代码分析执行流程 核心语法注释单行注释多行注释注释示例 关键字常量变量计算机进制数据类型标识符键盘录入 运算符算术运算符比较运算符赋值运算符自增减运算符逻辑运算符三元运算符逗号运算符运算符的优先级 流程控制语句顺序结构分支结构…

【Portswigger 学院】CORS

教程和靶场来源于 Burpsuite 的官网 Portswigger&#xff1a;Cross-origin resource sharing (CORS) - PortSwigger 跨域资源共享&#xff08;Cross-origin resource sharing&#xff0c;CORS&#xff09;是一种浏览器机制&#xff0c;允许浏览器访问不同源的资源。同源策略的作…

32.双击列表启动目标游戏

上一个内容&#xff1a;31.加载配置文件中的游戏到辅助列表 以 31.加载配置文件中的游戏到辅助列表 它的代码为基础进行修改 效果图&#xff1a; 添加列表双击事件 实现代码&#xff1a; LPNMITEMACTIVATE pNMItemActivate reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR…

送检了200多款主食冻干,花费百万后,我测评了VE、希喂、朗诺!

主食冻干真是养猫的好帮手&#xff0c;方便、易喂&#xff0c;还能为猫咪提供全面营养&#xff01;它模拟了猫咪的自然捕猎饮食&#xff0c;采用低温脱水和灭菌技术制成。这样的主食冻干不仅让铲屎官们的喂养变得轻松&#xff0c;还满足了猫咪的味蕾和营养需求。更重要的是&…

Orangepi Zero2

1、Orangepi Zero2 Orangepi Zero2 是基于全志H616的一款产品 特性&#xff1a; CPU全志H616四核64位1.5GHz高性能Cortex-A53处理器 GPU MaliG31MP2 SupportsOpenGLES1.0/2.0/3.2、OpenCL2.0 运行内存1GB DDR3(与GPU共享) 存储TF卡插槽&#xff0c;测试128G可支持、2MB SPI Fl…

【android】json

设置第potition个数据项的view的属性 成功显示数据项&#xff0c;熟悉recycleview三个方法 新建页面&#xff0c;定义适配器&#xff0c;指定使用MyViewHolder类对象保存每个数据胡view组件 padding-内部边距 bold-加粗 新建类&#xff0c;描述新闻内容 定义组件 public i…

MYSQL无法启动的修复过程

记录一次MySQ无法启动的修复过程。 1. 错误表现 今天在用python操作数据库时可能有些错误&#xff08;具体来说就是我尝试创建了一个已经存在的database&#xff09;&#xff0c;结果我发现MySQL中的那个database不存在了&#xff0c;我重启了一下电脑&#xff0c;结果mysql…

Webpack源码深入-webpack和webpack-cli

webpack源码深入-webpack和webpack-cli webpack命令工作原理如下 webpack指令 // webpack/package.json {..."mian":"lib/index.js","bin": {"webpack": "bin/webpack.js"},... }webpack指令的入口是webpack.js。 首先…

数据质量管理-规范性管理

数据质量管理简介 数据质量管理是一个持续性的管理动作&#xff0c;有些人在做数据质量管理的时候会陷入一步到位的误区&#xff0c;想要通过一个工具、平台&#xff0c;或者一套质检规则就完成整体的数据质量管理&#xff0c;而实际数据质量管理从数据接入的那一刻就需要介入…

rockchip linux sdk指定编译配置文件

SDK&#xff1a;rk3568_linux4.19_V1.4.0 硬件平台&#xff1a;RK3566 一、指定板级配置文件 板级配置文件在<SDK>/device/rockchip/rk3566_rk3568目录下。 1、方法1 ./build.sh后⾯加上板级配置⽂件&#xff0c;例如&#xff1a; ./build.sh /device/rockchip/rk3…

《数字图像处理(面向新工科的电工电子信息基础课程系列教材)》封面五年构想

禹晶、肖创柏、廖庆敏《数字图像处理&#xff08;面向新工科的电工电子信息基础课程系列教材&#xff09;》 2028年再版时&#xff0c;我要组个九宫图&#xff0c;构思中。。。

AI教育的“智”变大考,小度率先提交答卷!!

目录 01 LLM重定义“AI教师” 02 全新小度&#xff0c;换上“最强大脑” 03 智能原生&#xff1a;AI硬件破局的关键 作为继OpenAI、微软和谷歌之后&#xff0c;万众期待的最后一个尖子生&#xff0c;苹果在上周的WWDC24全球开发者大会上&#xff0c;终于交出了自己的“AI答卷…

【java分布式计算】分布式计算程序设计基础

期末复习 自留 重点只抓考点 目录 基本技术 SOCKETS网络套接字 多线程 数据序列化 Java I/O流 集合容器 范型 内部类、匿名类、Lambda&#xff08;代码&#xff09; 项目构建管理工具 高级技术 注解&#xff08;代码&#xff09; 反射&#xff08;代码&#xff09;…

信息学奥赛初赛天天练-29-CSP-J2022阅读程序-掌握递归、递推、动态规划、二分与极值函数应用

PDF文档公众号回复关键字:20240619 2022 CSP-J 阅读程序2 阅读程序(判断题1.5分 选择题3分 共计40分 ) 01 #include <algorithm> 02 #include <iostream> 03 #include <limits> 04 05 using namespace std; 06 07 const int MAXN 105; 08 const int MAX…

使用docker离线制作es镜像,方便内网环境部署

1、自己在本地安装docker以及docker-compose 2、拉取elasticsearch镜像 docker pull elasticsearch:7.14.0 docker pull kibana:7.14.0 3、将拉取到的镜像打包到本地目录 docker save elasticsearch:7.14.0 -o /Users/yanjun.hou/es/elasticsearch-7.14.0.tar docker save kib…

application/x-www-form-urlencoded和json的区别

application/x-www-form-urlencoded 和 application/json 是两种不同的数据格式&#xff0c;常用于HTTP请求中传递数据。 它们各自的特点和使用场景如下&#xff1a; 1. application/x-www-form-urlencoded •特点&#xff1a;这是一种传统的表单提交时采用的编码类型&#x…

# 消息中间件 RocketMQ 高级功能和源码分析(五)

消息中间件 RocketMQ 高级功能和源码分析&#xff08;五&#xff09; 一、 消息中间件 RocketMQ 源码分析&#xff1a;NameServer 路由元数据 1、消息中间件 RocketMQ 中&#xff0c;NameServer 路由管理 NameServer 的主要作用是为消息的生产者和消息消费者提供关于主题 To…

相交链表(Leetcode)

题目分析&#xff1a; . - 力扣&#xff08;LeetCode&#xff09; 相交链表&#xff1a;首先我想到的第一个思路是&#xff1a;如图可知&#xff0c;A和B链表存在长度差&#xff0c;从左边一起遍历链表不好找交点&#xff0c;那我们就从后面开始找&#xff0c;但是这是单链表&…