初阶1 入门

本章重点

  1. C++的关键字
  2. 命名空间
  3. C++的输入输出
  4. 缺省参数
  5. 函数重载
  6. 引用
  7. 内联函数
  8. auto关键字
  9. 基于范围的for循环
  10. 指针的空值nullptr

1.C++的关键字

c++总共有63个关键字,其中包含c语言的32个

这些关键字不需要特意去记,在我们日后写代码的过程中会慢慢用到并记住。

请添加图片描述

2.命名空间

在 C / C++ 中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。

2.1 命名冲突

#include <stdio.h>
#include <stdlib.h>int rand = 10;
// C语言没办法解决类似这样的命名冲突问题,所以C++提出了namespace来解决
int main()
{printf("%d\n", rand);	// stdlib库中有一个函数randreturn 0;
}
// 编译后后报错:error C2365: “rand”: 重定义;以前的定义是“函数”

namespace就可以解决这样的冲突

2.2 命名空间的定义

定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。

  • 一个命名空间定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中

//局部域->全局域->展开(编译时是否去命名空间)了的命名空间域 or 指定访问命名空间域

正常定义:

namespace zhangsan
{// 命名空间中可以定义变量/函数/类型int rand = 10;int Add(int left, int right){return left + right;}struct Node{struct Node* next;int val;};
}

嵌套定义:

命名空间可以嵌套定义

// test.cpp
namespace N1
{int a;int b;int Add(int left, int right){return left + right;}namespace N2{int c;int d;int Sub(int left, int right){return left - right;}}
}

多文件定义:

同一个工程中可以定义多个同名的命名空间,最后编译的时候编译器会将这多个命名空间合并成一个。

// test.h
namespace N1
{int Mul(int left, int right){return left * right;}
}

效果:

namespace N1
{int a;int b;int Add(int left, int right){return left + right;}namespace N2{int c;int d;int Sub(int left, int right){return left - right;}}int Mul(int left, int right){return left * right;}
}

2.3 命名空间的使用

定义一个命名空间:

namespace N1
{int a;int b;int Add(int left, int right){return left + right;}
}

如果想要使用命名空间中的成员有以下三种方法:

  • 加命名空间名称及作用域限定符
int main()
{printf("%d\n", N::a);return 0;
}
  • 使用using引入命名空间中的成员
using N::b;
int main()
{printf("%d\n", N::a);printf("%d\n", b);return 0;
}
  • 使用using namespace直接展开命名空间
using namespce N;
int main()
{printf("%d\n", N::a);printf("%d\n", b);Add(10, 20);return 0;
}

在项目中一般不直接展开命名空间,这样会导致命名污染,但是在平常练习时还是展开命名空间较为方便
也可以部分(指定)展开 using std::cout;

3.C++的输入输出

我们来看下C++是如何来实现问候的。

#include<iostream>
// std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
using namespace std;
int main()
{cout<<"Hello world!!!"<<endl;return 0;
}

说明:

  1. 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件
    以及按命名空间使用方法使用std。
  2. cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含<
    iostream >头文件中。
  3. <<是流插入运算符,>>是流提取运算符。
  4. 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。
    C++的输入输出可以自动识别变量类型。
  5. 实际上cout和cin分别是ostream和istream类型的对象,>>和<<也涉及运算符重载等知识,
    这些知识我们我们后续才会学习,所以我们这里只是简单学习他们的使用。后面我们还有一个章节更深入的学习IO流用法及原理。

注意:早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应
头文件即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,
规定C++头文件不带.h;旧编译器(vc 6.0)中还支持<iostream.h>格式,后续编译器已不支持,因此推荐使用+std的方式。

#include <iostream>
using namespace std;
int main()
{int a;double b;char c;// 可以自动识别变量的类型cin>>a;cin>>b>>c;cout<<a<<endl;cout<<b<<" "<<c<<endl;return 0;
}

std命名空间的使用惯例:

std是C++标准库的命名空间,如何展开std使用更合理呢?

  1. 在日常练习中,建议直接using namespace std即可,这样就很方便。
  2. using namespace std展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对象/函数,就存在冲突问题。
    该问题在日常练习中很少出现,但是项目开发中代码较多、规模大,就很容易出现。
    所以建议在项目开发中使用,像std::cout这样使用时指定命名空间 +
    using std::cout展开常用的库对象/类型等方式。

4.缺省参数

4.1 缺省参数概念

缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。

void Func(int a = 0)
{cout<<a<<endl;
}
int main()
{Func();     // 没有传参时,使用参数的默认值Func(10);   // 传参时,使用指定的实参return 0;
}

4.2 缺省参数种类

全缺省函数

函数参数都有缺省值

void Func(int a = 10, int b = 20, int c = 30)
{cout<<"a = "<<a<<endl;cout<<"b = "<<b<<endl;cout<<"c = "<<c<<endl;
}

半缺省参数

只有部分参数有缺省值:

void Func(int a, int b = 10, int c = 20)
{cout<<"a = "<<a<<endl;cout<<"b = "<<b<<endl;cout<<"c = "<<c<<endl;
}

注意:

  1. 半缺省参数必须从右往左依次来给出不能间隔着给
  2. 缺省参数不能在函数声明和定义中同时出现(只在声明中出现)
  3. 缺省值必须是常量或者全局变量
  4. C语言不支持(编译器不支持)

5.函数重载

5.1 函数重载概念

函数重载: 是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。

5.2 重载方式

  • 参数类型不同
int Add(int left, int right)
{cout << "int Add(int left, int right)" << endl;return left + right;
}double Add(double left, double right)
{cout << "double Add(double left, double right)" << endl;return left + right;
}
  • 参数个数不同
void f()
{	cout << "f()" << endl;
}void f(int a)
{cout << "f(int a)" << endl;
}
  • 参数类型顺序不同
void f(int a, char b)
{cout << "f(int a,char b)" << endl;
}void f(char b, int a)
{cout << "f(char b, int a)" << endl;
}

5.3 重载原理

每个C/C++程序都会经历预处理、编译、汇编、链接,在汇编阶段会生成符号表,然后在链接阶段进行符号重定位等一系列操作,保证函数在程序运行期间能够成功调用。

进阶7-程序环境与预处理

Stack.h Stack.cpp Text.cpp
//预处理: 头文件展开/宏替换/条件编译/去掉注释…

Stack.i Test.i
//编译: 检查语法,生成汇编代码

Stack.s Test.s
//汇编: 汇编代码转变为机器代码(二进制代码)

Stack.o Test.o
//链接: 生成可执行程序 (xxx.exe/a.out)

这里汇编阶阶段生成的符号表就是问题的关键所在,我们可以通过分别查看C语言的符号表和C++的符号表:

C语言符号表

#include <stdio.h>                     
int add(int a, int b)
{return a + b;
}void func(int a, double b)
{printf("func(int a, double b);\n");
}int main()
{return 0;
}

请添加图片描述

符号表里面只有函数名

C++符号表

#include <stdio.h> 
int add(int a, int b)
{return a + b;
}double add(double a, double b)
{return a + b;
}void func(int a, double b, int* ptr)
{printf("func(int a, double b, int* ptr);\n");
}int main()
{return 0;
}

请添加图片描述

符号表中的函数名后面将函数的参数带上了

6.引用

6.1 引用概念

引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间

引用的声明方法: 类型标识符 &引用名=目标变量名

int a = 10;
int& ra = a;//<====定义引用类型

注意:引用类型必须和引用实体是同种类型

注意: 引用类型必须和引用实体是同种类型的

6.2 引用的特性

  1. 引用在定义时必须初始化
int a = 10;
int& ra = a;//<====定义引用类型
int& rb; // err
  1. 一个变量可以有多个引用
int a = 10;
int& ra = a;//<====定义引用类型
int& rb = a;
int& rra = ra;	// 引用的引用 = 变量的引用
  1. 引用一旦引用一个实体,再不能引用其他实体
int a = 10;
int b = 20;
int& ra = a;//<====定义引用类型
ra = b;	// 对a进行赋值

6.3 常引用

常量与const修饰的变量的引用也要具有常性

void TestConstRef()
{const int a = 10;//int& ra = a; // 该语句编译时会出错,a为常量(权限不能放大)const int& ra = a;// int& b = 10; // 该语句编译时会出错,b为常量const int& b = 10;	//将b->10绑定(只能绑定常量),int&b = 10是错的int c = 10;const int& rc = c;  // 权限可以缩小double d = 12.34;//int& rd = d; // 该语句编译时会出错,类型不同const int& rd = d;  //与b同理
}

注意:
强制类型转换时会产生临时变量,再将临时变量赋值给指定值,而临时变量具有常性(如:数字10,字符’a’等);

double dd=11.1;
int ii=dd;
int& rii=dd;  //err
const int& crii=dd;   //right

6.4 使用场景

6.4.1 做参数

先看一段代码:

//C语言的传址调用
void Swap1(int* p1, int* p2) {int temp = *p1;*p1 = *p2;*p2 = temp;
}//C++的引用调用
void Swap2(int& rx, int& ry) {int temp = rx;rx = ry;ry = temp;
}int main()
{int x = 3, y = 6;Swap1(&x, &y); // C传参Swap2(x, y); // C++传参return 0;
}

这里引用就相当于再swap2的函数定义是,给参数用一个引用(起一个别名),引用的改变,原来的数也会改变

能明显发现,使用引用的方法,来替换指针的使用,能更方便一点
引用作参数使用场景

  1. 输出型参数
  2. 大对象/深拷贝对象 (提高效率)

6.4.2 做返回值

下面这段代码中,我们再func里面定义了一个变量,出了作用域,n会销毁,编译器这时会用一个临时变量来记录n的值,编译器创建的临时变量时被const所修饰的,最会将n的值赋值给ret

int func() 
{int n = 0;n++;return n;
}
int main()
{int ret = func();cout << ret << endl;ret = Cout();cout << ret << endl;return 0;
}

但如果我们返回的数据必须是被 static 修饰,或者是 动态开辟 的,再或者是 全局变量 等一些不会随着函数调用的结束而被销毁的数据,就可以使用引用做返回值

int& func() 
{static int n = 0;n++;return n;
}
int main()
{int ret = func();cout << ret << endl;ret = Cout();cout << ret << endl;return 0;
}
int& func() 
{static int n = 0;n++;return n;
}
int main()
{int& ret = func();//相当于int& a=b,&c=a;cout << ret << endl;ret = Cout();cout << ret << endl;return 0;
}

那么用引用返回有什么好处呢?

  • 用引用返回,就会避免编译器产生临时变量,如果你返回的是一个结构一个类,那么这个临时变量会变得很大,会降低代码的效率
  • 读写返回值

总结:

如果函数返回时,出了函数作用域,返回对象未销毁,则可以使用引用返回;
如果已经还给系统了,则必须使用传值返回。

6.5 引用和指针的区别

  1. 引用概念上定义一个变量的别名,指针存储一个变量地址。

  2. 引用在定义时必须初始化,指针没有要求

  3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体

  4. 没有NULL引用,但有NULL指针

  5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)

  6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小

  7. 有多级指针,但是没有多级引用

  8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理

  9. 引用比指针使用起来相对更安全

7.内联函数

关键字:inline

inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数会提升程序运行的效率。

普通函数:
请添加图片描述
内联函数:

请添加图片描述

C语言中的同样有内联函数的功能但是宏的缺点过于明显:

  1. 可读性差
  2. 宏由于类型无关,也就不够严谨。
  3. 宏可能会带来运算符优先级的问题,导致程序容易出现错。
  4. 宏是没法调试的。
  5. 内联函数继承了宏的优点的同时,又解决了宏的缺点,所以在平时尽量使用内联函数来替代宏。

特性

  1. inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷: 可能会使目标文件变大,优势: 少了调用开销,提高程序运行效率。
  2. inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、频繁调用的函数采用inline修饰,否则编译器会忽略inline特性
  3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

8.auto关键字

在早期,使用auto修饰的变量,是具有自动存储器的局部变量。

在C++11 中:auto不再是一个存储类型指示符,而是作为一个新的类型
指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。

使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。

8.1 使用规则

  1. auto与指针和引用结合起来使用

用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&

int x = 10;
auto a = &x;
auto* b = &x;
auto& c = x;cout << typeid(a).name() << endl;
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
  1. 在同一行定义多个变量

当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

auto a = 1, b = 2;
auto c = 3, d = 4.0; // 该行代码会编译失败,因为c和d的初始化表达式类型不同

8.2 不能推导的场景

  1. auto不能作为函数的参数
// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a);
  1. uto不能直接用来声明数组
int a[] = {1,2,3};
auto b[] = {4,5,6};  // err

9.范围for

9.1 使用语法

for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围

for (auto e : array)

9.2 使用条件

for循环迭代的范围必须是确定的对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供beginend的方法,beginend就是for循环迭代的范围。

void TestFor(int array[])	// 数组名传参会退化为首地址,找不到尾
{for(auto& e : array) 	// errcout<< e <<endl;
}

10.指针的空值nullptr

在良好的C/C++编程习惯中,声明一个变量时最好给该变量一个合适的初始值,否则可能会出现 不可预料的错误,比如未初始化的指针。

如果一个指针没有合法的指向,我们基本都是按照如下 方式对其进行初始化:

void TestPtr() 
{int* p1 = NULL;int* p2 = 0;
}

NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:

#ifndef NULL
#ifdef __cplusplus
#define NULL   0
#else
#define NULL   ((void *)0)
#endif
#endif

可以看到,NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,比如:

void f(int)
{cout << "f(int)" << endl;
}
void f(int*)
{cout << "f(int*)" << endl;
}
int main()
{f(0);f(NULL);f((int*)NULL);return 0;
}

程序本意是想通过f(NULL)调用指针版本的f(int*)函数,

但是由于NULL被定义成0,因此与程序的初衷相悖。

注意:

  • 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。
  • 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
  • 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。

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

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

相关文章

动态规划DP 数字三角形模型(模型分析+例题分析+C++代码实现)(数字三角形、摘花生、最低通行费用、方格取数、传纸条)

总体概览 数字三角形 原题链接 AcWing 898.数字三角形 题目描述 给定一个如下图所示的数字三角形&#xff0c;从顶部出发&#xff0c;在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点&#xff0c;一直走到底层&#xff0c;要求找出一条路径&#xff0c;使路…

C#/.NET/.NET Core技术前沿周刊 | 第 23 期(2025年1.20-1.26)

前言 C#/.NET/.NET Core技术前沿周刊&#xff0c;你的每周技术指南针&#xff01;记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿&#xff0c;助力技术成长与视野拓宽。 欢迎投稿、推荐…

力扣hot100链表总结-day0127

目录 206.反转链表&#xff08;0127&#xff09; 19.删除链表的倒数第N个节点&#xff08;0127&#xff09; 206.反转链表&#xff08;0127&#xff09; 总结&#xff1a; 1.迭代实现&#xff1a;将给出的头节点head固定&#xff0c;始终把head的下一个节点给安装成新头节点…

安宝特方案 | AR在供应链管理中的应用:提升效率与透明度

随着全球化的不断深入和市场需求的快速变化&#xff0c;企业对供应链管理的要求也日益提高。如何在复杂的供应链环境中提升效率、降低成本&#xff0c;并确保信息的透明度&#xff0c;成为了各大行业亟待解决的问题。而增强现实&#xff08;AR&#xff09;技术&#xff0c;特别…

力扣111二叉树的最小深度(DFS)

Problem: 111. 二叉树的最小深度 文章目录 题目描述思路复杂度Code 题目描述 思路 1.欲望求出最短的路径&#xff0c;先可以记录一个变量minDepth&#xff0c;同时记录每次当前节点所在的层数currentDepth 2.在递的过程中&#xff0c;每次递一层&#xff0c;也即使当前又往下走…

python -m pip和pip的主要区别

python -m pip和pip的主要区别在于它们与Python环境的关联方式和安装路径。‌ ‌与Python环境的关联方式‌&#xff1a; pip 是直接使用命令行工具来安装Python包&#xff0c;不指定特定的Python解释器。如果系统中存在多个Python版本&#xff0c;可能会导致安装的包被安装到…

RHEL封闭环境部署zabbix

背景&#xff1a;client端操作系统升级.然后安装了该操作系统基础版本的zabbix-client&#xff0c;与原来的zabbix-server版本不匹配&#xff0c;需要重新部署一台zabbix-server zabbix-server GUI上该client采集不到系统数据 说明&#xff1a;下文的 x.x.x.x 代表服务端的IP…

vim 中粘贴内容时提示: -- (insert) VISUAL --

目录 问题现象&#xff1a;解决方法&#xff1a;问题原因&#xff1a; 问题现象&#xff1a; 使用 vim 打开一个文本文件&#xff0c;切换到编辑模式后&#xff0c;复制内容进行粘贴时有以下提示&#xff1a; 解决方法&#xff1a; 在命令行模式下禁用鼠标支持 :set mouse …

数据结构与算法-要点整理

知识导图: 一、数据结构 包含:线性表(数组、队列、链表、栈)、散列表、树(二叉树、多路查找树)、图 1.线性表 数据之间就是“一对一“的逻辑关系。 线性表存储数据的实现方案有两种,分别是顺序存储结构和链式存储结构。 包含:数组、队列、链表、栈。 1.1 数组…

二级C语言题解:统计奇偶个数以及和与差、拼接字符串中数字并计算差值、提取字符串数组中单词尾部字母

目录 一、程序填空 --- 统计奇偶个数以及和与差 题目 分析 二、程序修改 --- 拼接字符串中数字并计算差值 题目 分析 三、程序设计题 --- 提取字符串数组中单词尾部字母 题目 分析 前言&#xff1a; 本节讲解C语言二级的统计奇偶个数以及和与差、拼接字符串中数字并计…

【四川乡镇界面】图层shp格式arcgis数据乡镇名称和编码2020年wgs84无偏移内容测评

本文将详细解析标题和描述中提到的IT知识点&#xff0c;主要涉及GIS&#xff08;Geographic Information System&#xff0c;地理信息系统&#xff09;技术&#xff0c;以及与之相关的文件格式和坐标系统。 我们要了解的是"shp"格式&#xff0c;这是一种广泛用于存储…

关于MySQL InnoDB存储引擎的一些认识

文章目录 一、存储引擎1.MySQL中执行一条SQL语句的过程是怎样的&#xff1f;1.1 MySQL的存储引擎有哪些&#xff1f;1.2 MyIsam和InnoDB有什么区别&#xff1f; 2.MySQL表的结构是什么&#xff1f;2.1 行结构是什么样呢&#xff1f;2.1.1 NULL列表&#xff1f;2.1.2 char和varc…

2018年全国硕士研究生入学统一考试管理类专业学位联考英语(二)试题-解析版

&#x1f3e0;个人主页&#xff1a;fo安方的博客✨ &#x1f482;个人简历&#xff1a;大家好&#xff0c;我是fo安方&#xff0c;目前中南大学MBA在读&#xff0c;也考取过HCIE Cloud Computing、CCIE Security、PMP、CISP、RHCE、CCNP RS、PEST 3等证书。&#x1f433; &…

高可用集群故障之join

本文记录了在部署高可用的k8s集群时&#xff0c;遇到的一个故障及其解决方法。 集群环境 描述&#xff1a;三主三从&#xff0c;eth0为外网网卡&#xff0c;eth1为内网网卡&#xff0c;内网互通。 需求&#xff1a;eth0只负责访问外网&#xff0c;eth1作为集群间的通信。 主…

FPGA实现任意角度视频旋转(完结)视频任意角度旋转实现

本文主要介绍如何基于FPGA实现视频的任意角度旋转&#xff0c;关于视频180度实时旋转、90/270度视频无裁剪旋转&#xff0c;请见本专栏前面的文章&#xff0c;旋转效果示意图如下&#xff1a; 为了实时对比旋转效果&#xff0c;采用分屏显示进行处理&#xff0c;左边代表旋转…

RocketMQ原理—5.高可用+高并发+高性能架构

大纲 1.RocketMQ的整体架构与运行流程 2.基于NameServer管理Broker集群的架构 3.Broker集群的主从复制架构 4.基于Topic和Queue实现的数据分片架构 5.Broker基于Pull模式的主从复制原理 6.Broker层面到底如何做到数据0丢失 7.数据0丢失与写入高并发的取舍 8.RocketMQ读…

一文简单回顾Java中的String、StringBuilder、StringBuffer

简单说下String、StringBuilder、StringBuffer的区别 String、StringBuffer、StringBuilder在Java中都是用于处理字符串的&#xff0c;它们之间的区别是String是不可变的&#xff0c;平常开发用的最多&#xff0c;当遇到大量字符串连接的时候&#xff0c;就用StringBuilder&am…

Go:基于Go实现一个压测工具

文章目录 写在前面整体架构通用数据处理模块Http请求响应数据处理Curl参数解析处理 客户端模块Http客户端处理Grpc客户端处理Websocket客户端处理 连接处理模块GrpcHttp 统计数据模块统计原理实现过程 写在前面 本篇主要是基于Go来实现一个压测的工具&#xff0c;关于压测的内…

Redis --- 分布式锁的使用

我们在上篇博客高并发处理 --- 超卖问题一人一单解决方案讲述了两种锁解决业务的使用方法&#xff0c;但是这样不能让锁跨JVM也就是跨进程去使用&#xff0c;只能适用在单体项目中如下图&#xff1a; 为了解决这种场景&#xff0c;我们就需要用一个锁监视器对全部集群进行监视…

小盒科技携手体验家,优化智能教育服务体验,打造在线教育新高度

北京小盒科技有限公司&#xff08;简称“小盒科技”&#xff0c;由“作业盒子”更名而来&#xff09;是一家专注于教育科技的公司&#xff0c;致力于利用人工智能、大数据等先进技术&#xff0c;为中小学教育提供创新的解决方案和产品。 近日&#xff0c;「小盒科技」携手体…