【C++】 string类的模拟实现

目录

一、我们先创建三个文件分别为 String.h(声明)、String.cpp(定义)、teat.cpp(测试)

二、成员函数 

构造函数与析构函数

🌟string()

🌟string(const char* str)

🌟~string() 

🌟深拷贝string(const string& s) 

遍历字符串

🌟operator[ ]

🌟iterator 迭代器

对内容的修改

🌟reserve 开空间

🌟push_back 尾插

🌟append 尾插字符串

🌟operator+= 字符串追加

🌟insert 在指定位置插入字符或字符串

🌟erase 删除

🌟find 查找字符或字符串

🌟substr 在str中从pos位置开始,截取n个字符,然后将其返回

几个重载函数

🌟operator= 赋值重载

🌟operator== / < 等几个比较函数

三、非成员函数 

🌟流插入和流提取

四、完整代码


我们实现的是basic_string:

一、我们先创建三个文件分别为 String.h(声明)、String.cpp(定义)、teat.cpp(测试)

二、成员函数 

构造函数与析构函数

🌟string()

空字符串构造:

String::String()
{_str = new char[1] {'\0'};_size = 0;_capacity = 0;
}

这里我们给字符数组分配一个空间大小来储存\0 ,同时设置类的_size和_capacity成员变量的初始值。

 一些细节:

以上涉及到相关的接口实现往接着下看😊 

🌟string(const char* str)

常量字符串来实例化一个对象:

	String::String(const char* str):_str(new char[strlen(str) + 1])//+1给末尾存储\0, _size(strlen(str)), _capacity(strlen(str)){strcpy(_str, str);//用字符串函数将常量字符串拷贝到对象的数组中}

我们可以对代码进行优化,可以将上述两个函数通过缺省值合并为一个函数 。

String::String(const char* str=""):_size(strlen(str))
{_str = new char[_size + 1];// +1是给末尾存储\0_capacity = _size;strcpy(_str, str); //用字符串函数将常量字符串拷贝到对象的数值中
}

缺省值即为空字符串,初始化列表只为size赋值减少对strlen的多次调用。 

一些细节:

 全缺省参数该怎样声明呢?

🌟~string() 

析构函数

	String::~String(){delete[] _str;_str = nullptr;_size = _capacity = 0;}

🌟深拷贝string(const string& s) 

系统默认的拷贝是浅拷贝,对象拷贝的时候是按字节一个一个拷贝,对内置类型默认生成的拷贝构造就是完成浅拷贝/值拷贝,会导致两个字符串同时指向同一个空间,在析构时可能会造成多次释放使系统崩溃。

 因此需要手动实现深拷贝:

String::String(const String& s)
{_str = new char[s._capacity + 1];//开新的空间strcpy(_str, s._str);//把旧空间的内容拷贝到新的空间_size = s._size;_capacity = s._capacity;	
}

遍历字符串

首先我们用三个函数来获取三个成员变量:

我们这里设置为const成员函数,使String类对象和const String类对象都可以调用这几个函数。

	const char* String::c_str() const{return _str;}size_t String::size() const{return _size;}size_t String::capacity() const{return _capacity;}

🌟operator[ ]

<分为两种>

第一种:允许对字符串内容进行修改

	char& String::operator[](size_t pos){assert(pos < _size);//string会抛异常return _str[pos];//返回值为 char*}

第二种:不能修改类的成员变量

const char& String::operator[](size_t pos) const{assert(pos < _size);return _str[pos];//返回值为 const char*}

🌟iterator 迭代器

<分为两种>

非常量:

//String.htypedef char* iterator;iterator begin();iterator end();//String.cppString::iterator String::begin()// char* {return _str;}String::iterator String::end(){return _str + _size;}

常量: 不是本身不可以修改,要保证的是指向的内容不能修改。

//String.htypedef const char* const_iterator;const_iterator begin() const;const_iterator end() const;//String.cppString::const_iterator String::begin() const//const char*{return _str;}String::const_iterator String::end() const{return _str + _size;}

 测试:

	// 封装:屏蔽了底层实现细节,// 提供了一种简单通用访问容器的方式xlf::String s1("hello world");xlf::String::iterator it1 = s1.begin();while (it1 != s1.end()){cout << *it1 << " ";++it1;}cout << endl;for (auto e : s1){cout << e << " ";}cout << endl;const xlf::String s2("xxxxxxx");xlf::String::const_iterator it2 = s2.begin();while (it2 != s2.end()){// *it2 = 'y';//本身不能修改cout << *it2 << " ";++it2;}cout << endl;for (size_t i = 0; i < s2.size(); i++){//s2[i]++;//本身不能修改cout << s2[i] << " ";//只能访问}cout << endl;

对内容的修改

🌟reserve 开空间

void String::reserve(size_t n)
{if (n > _capacity){char* tmp = new char[n + 1];//开一个更大的空间  +1存储\0strcpy(tmp, _str);//拷贝旧空间的内容,到新空间delete[] _str;//先释放旧空间_str = tmp;//指向新空间_capacity = n;//能存储有效字符个数的空间}
}

🌟push_back 尾插

	void String::push_back(char ch){if (_size == _capacity)//先判断空间的大小{size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newcapacity);}_str[_size] = ch;_str[_size + 1] = '\0';//末尾填上\0++_size;}

🌟append 尾插字符串

	//"hello" "xxxxxxxxxxxxx"//append不能只扩容两倍void String::append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}strcpy(_str + len, str);//可直接找的\0,直接复制_size += len;}

🌟operator+= 字符串追加

//非常量String& String::operator+=(char ch){push_back(ch);return *this;}//常量String& String::operator+=(const char* str){append(str);return *this;}

 重载运算符的返回值:

内置类型用这个运算符的返回值是什么

自定义类型用这个运算符的返回值是什么

例:

int  i ;

i+=  的返回值是 i 

🌟insert 在指定位置插入字符或字符串

在讲insert之前我们先讲一个小知识:

我们知道静态成员变量,是在类内声明,在类外定义的

 补充小知识:

//插入一个字符void String::insert(size_t pos, char ch){assert(pos <= _size);if (_size == _capacity){size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newcapacity);}size_t end = _size;//size初始指向末尾\0位置,将数据不断往后挪,直到腾出pos位置while (end >= pos)//当pos位置为0时,end-会变成-1,//而无符号整型-1是一个很大的值,导致无法跳出循环{_str[end + 1] = _str[end];--end;}_str[pos] = ch;++_size;}改进:void String::insert(size_t pos, char ch){assert(pos <= _size);if (_size == _capacity){size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newcapacity);}size_t end = _size + 1;//end初始指向\0的下一个位置while (end > pos)//当end=pos时,跳出循环{_str[end] = _str[end - 1];--end;}_str[pos] = ch;++_size;}//插入一个字符串void String::insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}size_t end = _size + len;while (end >= pos + len){_str[end] = _str[end - len];--end;}memcpy(_str + pos, str, len);_size += len;}

🌟erase 删除

	void String::erase(size_t pos, size_t len){assert(pos < _size);//len大于前面字符个数时,有多少删多少if (len >= _size - pos){_str[pos] = '\0';_size = pos;}else//往前覆盖{//        目标             源strcpy(_str + pos, _str + pos + len);//将源字符串复制到目标字符串,包括\0//将pos+len的字符串覆盖到pos位置上_size -= len;}}

🌟find 查找字符或字符串

//查找字符size_t string::find(char ch, size_t pos){for (size_t i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;}//查找字符串size_t string::find(const char* sub, size_t pos){char* p = strstr(_str + pos, sub);//返回字符串中首次出现子串的地址return  p - _str;}

🌟substr 在str中从pos位置开始,截取n个字符,然后将其返回

string string::substr(size_t pos, size_t len){// len大于后面剩余字符,有多少取多少if (len > _size - pos){string sub(_str + pos);//直接构造return sub;}else{string sub;sub.reserve(len);for (size_t i = 0; i < len; i++){sub += _str[pos + i];}return sub;}}

几个重载函数

🌟operator= 赋值重载

String& String::operator=(const String& s)
{if (this != &s){char* tmp = new char[s._capacity + 1];//开一个新的空间(多开一个给\0)strcpy(tmp, s._str);//把s._str的内容拷贝到新开的空间delete[] _str;//释放旧空间_str = tmp;//指向新开的空间_size = s._size;//更改指向_capacity = s._capacity;//更改指向}return *this;//连续赋值
}

🌟operator== / < 等几个比较函数

复用:

	bool String::operator<(const String& s) const{return strcmp(_str, s._str) < 0;//两个字符串进行比较}bool String::operator>(const String& s) const{return !(*this <= s);}bool String::operator<=(const String& s) const{return *this < s || *this == s;}bool String::operator>=(const String& s) const{return !(*this < s);}bool String::operator==(const String& s) const{return strcmp(_str, s._str) == 0;}bool String::operator!=(const String& s) const{return !(*this == s);}

三、非成员函数 

🌟流插入和流提取

输入是对内容的覆盖,所以我们先实现一个clear()函数来清空字符串

void String::clear()
{_str[0] = '\0';_size = 0;
}

流插入:

	istream& operator>>(istream& is, String& str){str.clear();char ch = is.get();while (ch != ' ' && ch != '\n'){str += ch;//连续不断的+=会进行不断地扩容ch = is.get();}return is;}改进:istream& operator>>(istream& is, string& str){str.clear();char buff[128];//缓冲数组int i = 0;char ch = is.get();while (ch != ' ' && ch != '\n')//读到空格、换行退出{buff[i++] = ch;//0 - 126if (i == 127){buff[i] = '\0';str += buff;i = 0;}ch = is.get();}if (i != 0){buff[i] = '\0';str += buff;}return is;}

流提取:

	ostream& operator<<(ostream& os, const String& str){for (size_t i = 0; i < str.size(); i++){os << str[i];}return os;}

四、完整代码

//string.h
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;namespace xlf
{class String{public:typedef char* iterator;typedef const char* const_iterator;iterator begin();iterator end();const_iterator begin() const;const_iterator end() const;//String();String(const char* str = "");String(const String& s);String& operator=(const String& s);~String();const char* c_str() const;size_t size() const;char& operator[](size_t pos);const char& operator[](size_t pos) const;void reserve(size_t n);void push_back(char ch);void append(const char* str);String& operator+=(char ch);String& operator+=(const char* str);void insert(size_t pos, char ch);void insert(size_t pos, const char* str);void erase(size_t pos = 0, size_t len = npos);size_t find(char ch, size_t pos = 0);size_t find(const char* str, size_t pos = 0);void swap(String& s);String substr(size_t pos = 0, size_t len = npos);String& operator=(const String& s);bool operator<(const String& s) const;bool operator>(const String& s) const;bool operator<=(const String& s) const;bool operator>=(const String& s) const;bool operator==(const String& s) const;bool operator!=(const String& s) const;void clear();private:char* _str;size_t _size;size_t _capacity;const static size_t npos;};istream& operator>>(istream& is, String& str);ostream& operator<<(ostream& os, const String& str);
}string.cpp
#include"string.h"namespace xlf
{const size_t String::npos = -1;//要指定类域String::iterator String::begin()// char* {return _str;}String::iterator String::end(){return _str + _size;}String::const_iterator String::begin() const//const char*{return _str;}String::const_iterator String::end() const{return _str + _size;}String::String(const char* str):_size(strlen(str)){_str = new char[_size + 1];_capacity = _size;strcpy(_str, str);}String::String(const String& s){_str = new char[s._capacity + 1];//开新的空间strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;	}String& String::operator=(const String& s){if (this != &s){char* tmp = new char[s._capacity + 1];//开新的空间strcpy(tmp, s._str);//把旧空间的内容拷贝到新的空间delete[] _str;//释放旧空间_str = tmp;_size = s._size;_capacity = s._capacity;}return *this;}String::~String(){delete[] _str;_str = nullptr;_size = _capacity = 0;}const char* String::c_str() const{return _str;}size_t String::size() const{return _size;}char& String::operator[](size_t pos){assert(pos < _size);return _str[pos];}const char& String::operator[](size_t pos) const{assert(pos < _size);return _str[pos];}void String::reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];//开一个更大的空间  +1存储\0strcpy(tmp, _str);//拷贝旧空间的内容,到新空间delete[] _str;//先释放旧空间_str = tmp;//指向新空间_capacity = n;//能存储有效字符个数的空间}}void String::push_back(char ch){if (_size == _capacity)//先判断空间的大小{size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newcapacity);}_str[_size] = ch;_str[_size + 1] = '\0';//末尾填上\0++_size;}//"hello" "xxxxxxxxxxxxx"//append不能只扩容两倍void String::append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}strcpy(_str + len, str);//可直接找的\0,直接复制_size += len;}String& String::operator+=(char ch){push_back(ch);return *this;}String& String::operator+=(const char* str){append(str);return *this;}void String::insert(size_t pos, char ch){assert(pos <= _size);if (_size == _capacity){size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newcapacity);}size_t end = _size + 1;//end初始指向\0的下一个位置while (end > pos)//当end=pos时,跳出循环{_str[end] = _str[end - 1];--end;}_str[pos] = ch;++_size;}void String::insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}size_t end = _size + len;while (end >= pos + len){_str[end] = _str[end - len];--end;}memcpy(_str + pos, str, len);_size += len;}void String::erase(size_t pos, size_t len){assert(pos < _size);//len大于前面字符个数时,有多少删多少if (len >= _size - pos){_str[pos] = '\0';_size = pos;}else//往前覆盖{//        目标             源strcpy(_str + pos, _str + pos + len);//将源字符串复制到目标字符串,包括\0_size -= len;}}size_t String::find(char ch, size_t pos){for (size_t i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;}size_t String::find(const char* str, size_t pos){char* p = strstr(_str + pos, str);//返回字符串中首次出现子串的地址return p - _str;}void String::swap(String& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}String String::substr(size_t pos, size_t len){//len大于后面剩余字符,有多少取多少if (len > _size - pos){String sub(_str + pos);return sub;}else{String sub;sub.reserve(len);for (size_t i = 0; i < len; i++){sub += _str[pos + i];}return sub;}}String& String::operator=(const String& s){if (this != &s){char* tmp = new char[s._capacity + 1];//开一个新的空间(多开一个给\0)strcpy(tmp, s._str);//把s._str的内容拷贝到新开的空间delete[] _str;//释放旧空间_str = tmp;//指向新开的空间_size = s._size;//更改指向_capacity = s._capacity;//更改指向}return *this;//连续赋值}bool String::operator<(const String& s) const{return strcmp(_str, s._str) < 0;//两个字符串进行比较}bool String::operator>(const String& s) const{return !(*this <= s);}bool String::operator<=(const String& s) const{return *this < s || *this == s;}bool String::operator>=(const String& s) const{return !(*this < s);}bool String::operator==(const String& s) const{return strcmp(_str, s._str) == 0;}bool String::operator!=(const String& s) const{return !(*this == s);}void String::clear(){_str[0] = '\0';_size = 0;}istream& operator>>(istream& is, String& str){str.clear();char buff[128];//缓冲数组int i = 0;char ch = is.get();while (ch != ' ' && ch != '\n')//读到空格、换行退出{buff[i++] = ch;//0 - 126if (i == 127){buff[i] = '\0';str += buff;i = 0;}ch = is.get();}if (i != 0){buff[i] = '\0';str += buff;}return is;}ostream& operator<<(ostream& os, const String& str){for (size_t i = 0; i < str.size(); i++){os << str[i];}return os;}}

如若对你有帮助,记得点赞、收藏、关注哦!

若有误,望各位,在评论区留言或者私信我 指点迷津!!!谢谢^ ^ ~

 

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

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

相关文章

YOLO 模型基础入门及官方示例演示

文章目录 Github官网简介模式数据集Python 环境Conda 环境Docker 环境部署 CPU 版本官方 CLI 示例官方 Python 示例 任务目标检测姿势估计图像分类 Ultralytics HUB视频流示例 Github https://github.com/ultralytics/ultralytics 官网 https://docs.ultralytics.com/zhhttp…

python-网络并发模型

3. 网络并发模型 3.1 网络并发模型概述 什么是网络并发 在实际工作中&#xff0c;一个服务端程序往往要应对多个客户端同时发起访问的情况。如果让服务端程序能够更好的同时满足更多客户端网络请求的情形&#xff0c;这就是并发网络模型。 循环网络模型问题 循环网络模型只能…

跨平台WPF音乐商店应用程序

目录 一 简介 二 设计思路 三 源码 一 简介 支持在线检索音乐&#xff0c;支持实时浏览当前收藏的音乐及音乐数据的持久化。 二 设计思路 采用MVVM架构&#xff0c;前后端分离&#xff0c;子界面弹出始终位于主界面的中心。 三 源码 视窗引导启动源码&#xff1a; namesp…

知名在线市场 Etsy 允许在其平台上销售 AI 艺术品,但有条件限制|TodayAI

近日&#xff0c;以手工和复古商品著称的在线市场 Etsy 宣布&#xff0c;将允许在其平台上销售 AI 生成的艺术品。这一举措引发了广泛关注和争议。尽管 Etsy 正在接受 AI 艺术的潮流&#xff0c;但平台对这一类商品的销售设置了一些限制。 根据 Etsy 新发布的政策&#xff0c;…

51单片机(STC8H8K64U/STC8051U34K64)_RA8889驱动TFT大屏_I2C_HW参考代码(v1.3) 硬件I2C方式

本篇介绍单片机使用硬件I2C方式控制RA8889驱动彩屏。 提供STC8H8K64U和STC8051U34K64的参考代码。 【硬件部份】STC8H8K64U/STC8051U34K64 RA8889开发板 7寸TFT 800x480 1. 实物连接图&#xff1a;STC8H8K64URA8889开发板&#xff0c;使用P2口I2C接口&#xff1a; 2.实物连…

【QT】信号与槽(概述、使用、自定义、连接方式、其他说明)

一、信号和槽概述 在 Qt 中&#xff0c;用户和控件的每次交互过程称为一个事件。比如 “用户点击按钮” 是一个事件&#xff0c;“用户关闭窗口” 也是一个事件。每个事件都会发出一个信号&#xff0c;例如用户点击按钮会发出 “按钮被点击” 的信号&#xff0c;用户关闭窗口…

windows edge自带的pdf分割工具(功能)

WPS分割pdf得会员&#xff0c;要充值&#xff01;网上一顿乱找&#xff0c;发现最简单&#xff0c;最好用&#xff0c;免费的还是回到Windows。 Windows上直接在edge浏览器打开PDF&#xff0c;点击 打印 按钮,页面下选择对应页数 打印机 选择 另存为PDF&#xff0c;然后保存就…

记录一下在Hyper-v中动态磁盘在Ubuntu中不完全用到的问题(扩展根目录)

在之前给hyper虚拟机的Ubuntu分配磁盘有20G&#xff1b; 后来在Ubuntu中查看磁盘发现有一个分区没用到&#xff1a; 贴的图片是完成扩展后的 之前这里是10G&#xff0c;然后有个dev/sda4的分区&#xff0c;也是10G&#xff0c;Type是Microsoft Basic Data&#xff1b; …

【LeetCode】填充每个节点的下一个右侧节点指针 II

目录 一、题目二、解法完整代码 一、题目 给定一个二叉树&#xff1a; struct Node { int val; Node *left; Node *right; Node *next; } 填充它的每个 next 指针&#xff0c;让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点&#xff0c;则将 next 指针设置为 NUL…

spring security源码追踪理解(一)

一、前言 近期看了spring security相关的介绍&#xff0c;再加上项目所用若依框架的底层安全模块也是spring security&#xff0c;所以想从源码的角度加深下对该安全模块的理解&#xff08;看源码之前&#xff0c;我们要先有个意识&#xff0c;那就是spring security安全模块主…

【面试题】Redo log和Undo log

Redo log 介绍Redo log之前我们需要了解一下&#xff0c;mysql数据操作的流程&#xff1a; 上述就是数据操作的流程图&#xff0c;可以发现sql语句并不是直接操作的磁盘而是通过操作内存&#xff0c;然后进行内存到磁盘的一个同步。这里我们必须要了解一些区域&#xff1a; 缓…

c++基础(类和对象中)(类的默认成员函数)

目录 一.构造函数&#xff08;类似初始化&#xff09; 1.概念 2.构造函数的特点 二.析构函数&#xff08;类似 销毁对象/空间&#xff09; 三.拷贝构造函数(类似复制粘贴的一种 初始化 ) 1.概念&#xff1a; 2.拷贝构造的特点&#xff1a; 四.赋值运算符重载&#xff08…

IDEA的工程与模块管理

《IDEA破解、配置、使用技巧与实战教程》系列文章目录 第一章 IDEA破解与HelloWorld的实战编写 第二章 IDEA的详细设置 第三章 IDEA的工程与模块管理 第四章 IDEA的常见代码模板的使用 第五章 IDEA中常用的快捷键 第六章 IDEA的断点调试&#xff08;Debug&#xff09; 第七章 …

STM32的ADC详解

目录 一、ADC简介 二、ADC的时钟 三、ADC特性 四、ADC功能说明 五、规则通道和注入通道 1.规则通道 2.注入通道 3.区别 六、数据寄存器 1.右对齐 2.左对齐 七、转换模式 1.单次转换模式 2.续转换模式 3.扫描模式 4.区别 八、程序实现 1.需求 2.ADC初始化 3.A…

ipv6 基础学习(一)

IPv6 为什么要有IPV6&#xff1f; IPv4地址空间有限&#xff1a;IPv4使用32位地址&#xff0c;最多可提供约43亿个地址。随着互联网设备数量的爆炸式增长&#xff0c;这些地址已经几乎耗尽。 IPv6地址空间庞大&#xff1a;IPv6使用128位地址&#xff0c;可以提供大约3.410^3…

爬虫自己做的

1.urllib 1.1基本使用 1.2 下载&#xff08;图片&#xff0c;页面&#xff0c;视频&#xff09; 1.3 get 1.3.1 quote 中文变成对应uncode编码 当url 的wd中文时 quote是将中文变成对应uncode编码 然后拼接成完整的url 1.3.2urlencode方法 wd有多个参数 1.3.3ajas get实例 …

【Git远程操作】理解分布式管理 | 创建远程仓库

目录 1.理解分布式管理 多人协作开发 2.创建远程仓库 2.1仓库名&路径 2.2初始化仓库&设置模板 1.理解分布式管理 目前我们学习的所有内容都是在本地来完成的。&#xff08;add /commit /版本撤销回退/分支管理&#xff09; Git是一个分布式 的版本控制系统。 分支…

动漫风格动漫404网站维护HTML源码

源码介绍 动漫风格动漫404网站维护HTML源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面 效果预览 源码下载 动漫风格动漫404网站维护HTML源码

【存储学习笔记】1:机械硬盘(Hard Drive Disk)结构和寻址方式

目录 HDD的结构HDD的寻址方式CHS寻址&#xff08;不适用于等密度结构磁盘&#xff09;LBA寻址&#xff08;目前普遍使用的线性寻址方式&#xff09; HDD的寻址速度 HDD的结构 盘面&#xff08;Platter&#xff09;&#xff1a;单面或者双面覆盖着用于记录数据的磁性物质&#x…

Gateway源码分析:路由Route、断言Predicate、Filter

文章目录 源码总流程图说明GateWayAutoConfigurationDispatcherHandlergetHandler()handleRequestWith()RouteToRequestUrlFilterReactiveLoadBalancerClientFilterNettyRoutingFilter 补充知识适配器模式 详细流程图 源码总流程图 在线总流程图 说明 Gateway的版本使用的是…