string类详解(上)

文章目录

  • 目录
    • 1. STL简介
      • 1.1 什么是STL
      • 1.2 STL的版本
      • 1.3 STL的六大组件
    • 2. 为什么学习string类
    • 3. 标准库中的string类
      • 3.1 string类
      • 3.2 string类的常用接口说明

目录

  • STL简介
  • 为什么学习string类
  • 标准库中的string类
  • string类的模拟实现
  • 现代版写法的String类
  • 写时拷贝

1. STL简介

1.1 什么是STL

STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架

1.2 STL的版本

  • 原始版本

Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何人任意运用、拷贝、修改、传播、商业使用这些代码,无需付费。唯一的条件就是也需要向原始版本一样做开源使用。HP 版本–所有STL实现版本的始祖。

  • P. J. 版本

由P. J. Plauger开发,继承自HP版本,被Windows Visual C++采用,不能公开或修改,缺陷:可读性比较低,符号命名比较怪异。

  • RW版本

由Rouge Wage公司开发,继承自HP版本,被C+ + Builder 采用,不能公开或修改,可读性一般。

  • SGI版本

由Silicon Graphics Computer Systems,Inc公司开发,继承自HP版本。被GCC(Linux)采用,可移植性好,可公开、修改甚至贩卖,从命名风格和编程风格上看,阅读性非常高。我们后面学习STL要阅读部分源代码,主要参考的就是这个版本

1.3 STL的六大组件

STL的六大组件

2. 为什么学习string类

C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

3. 标准库中的string类

3.1 string类

string类的具体信息可以通过cplusplus网站进行查阅

在使用string类时,必须包含#include头文件以及using namespace std;

3.2 string类的常用接口说明

我们先来总的看一下string类的常用接口:

  1. string类对象的常见构造
    string类对象的常见构造
  2. string类对象的容量操作
    string类对象的容量操作
  3. string类对象的访问及遍历操作
    string类对象的访问及遍历操作
  4. string类对象的修改操作
    string类对象的修改操作
  5. string类非成员函数
    string类非成员函数

接下来,我们通过一些具体的场景来学习如何使用这些接口:

  • 如何构造一个string类对象
    string类对象的构造
#include <iostream>
#include <string>using namespace std;void test_string1()
{//常用string s1;string s2("hello world");string s3(s2);//不常用 了解string s4(s2, 3, 5);string s5(s2, 3);string s6(s2, 3, 30);string s7("hello world", 5);string s8(10, 'x');cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;cout << s4 << endl;cout << s5 << endl;cout << s6 << endl;cout << s7 << endl;cout << s8 << endl;cin >> s1;cout << s1 << endl;
}int main()
{test_string1();return 0;
}

补充:

void push_back(const string& s)
{}void test_string2()
{//构造string s1("hello world");//隐式类型转换string s2 = "hello world";const string& s3 = "hello world";push_back(s1);push_back("hello world");
}int main()
{test_string2();return 0;
}

  • string的遍历

第一种方法:

//class string
//{
//public:
//	//引用返回
//	//1. 减少拷贝
//	//2. 修改返回对象
//	char& operator[](size_t i)
//	{
//		assert(i < _size);
//
//		return _str[i];
//	}
//private:
//	char* _str;
//	size_t _size;
//	size_t _capacity;
//};void test_string3()
{string s1("hello world");cout << s1.size() << endl;//11//cout << s1.length() << endl;//11for (size_t i = 0; i < s1.size(); i++){s1[i]++;}s1[0] = 'x';//越界检查//s1[20];for (size_t i = 0; i < s1.size(); i++){//cout << s1.operator[](i) << " ";cout << s1[i] << " ";}cout << endl;const string s2("hello world");//不能修改//s2[0] = 'x';
}int main()
{test_string3();return 0;
}

size和operator[]
注: size() 与 length() 方法底层实现原理完全相同,引入 size() 的原因是为了与其他容器的接口保持一致,一般情况下基本都是用 size()

第二种方法:
iterator

void test_string4()
{string s1("hello world");//遍历方式2:迭代器string::iterator it1 = s1.begin();while (it1 != s1.end()){*it1 += 3;cout << *it1 << " ";++it1;}cout << endl;//cout << typeid(it1).name() << endl;
}int main()
{test_string4();return 0;
}

iterator的优势

void test_string4()
{list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);list<int>::iterator it = lt1.begin();while (it != lt1.end()){cout << *it << " ";++it;}cout << endl;
}int main()
{test_string4();return 0;
}

第三种方法:

void test_string4()
{string s1("hello world");//遍历方式3:范围for(通用的)//底层角度,它就是迭代器for (auto& e : s1){e++;//不会影响s1中的数据,它是一个赋值拷贝;要加上引用才会改变s1中的数据cout << e << " ";}cout << endl;cout << s1 << endl;list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);for (auto& e : lt1){cout << e << " ";}cout << endl;
}int main()
{test_string4();return 0;
}

注: 除了普通迭代器之外,还有

  1. const迭代器
    const迭代器
void test_string5()
{const string s1("hello world");//string::const_iterator it1 = s1.begin();auto it1 = s1.begin();while (it1 != s1.end()){//不能修改//*it1 += 3;cout << *it1 << " ";++it1;}cout << endl;
}int main()
{test_string5();return 0;
}
  1. 反向迭代器
    反向迭代器
void test_string5()
{string s2("hello world");string::reverse_iterator it2 = s2.rbegin();//auto it2 = s2.rbegin();while (it2 != s2.rend()){*it2 += 3;cout << *it2 << " ";++it2;}cout << endl;const string s3("hello world");string::const_reverse_iterator it3 = s3.rbegin();//auto it3 = s3.rbegin();while (it3 != s3.rend()){//不能修改//*it3 += 3;cout << *it3 << " ";++it3;}cout << endl;
}int main()
{test_string5();return 0;
}

  • 按字典序排序
    排序
#include <algorithm>void test_string6()
{string s1("hello world");cout << s1 << endl;//s1按字典序(ASCII码)排序//sort(s1.begin(), s1.end());//第一个和最后一个不参与排序//sort(++s1.begin(), --s1.end());//前5个排序sort(s1.begin(), s1.begin() + 5);cout << s1 << endl;
}int main()
{test_string6();return 0;
}
  • 插入字符
    append
void test_string7()
{string s1("hello world");cout << s1 << endl;s1.push_back('x');cout << s1 << endl;s1.append(" yyyyyy!!");cout << s1 << endl;string s2("111111");s1 += 'y';s1 += "zzzzzzzz";s1 += s2;cout << s1 << endl;
}int main()
{test_string7();return 0;
}

注: 在string尾部追加字符时,s.push_back(‘c’) / s.append(1, ‘c’) / s += ‘c’ 三种的实现方式差不多,一般情况下string类的 += 操作用的比较多,+= 操作不仅可以连接单个字符,还可以连接字符串

  • 关于修改的一些接口
    insert
void test_string8()
{string s1("hello world");cout << s1 << endl;s1.assign("111111");cout << s1 << endl;//慎用,因为效率不高 -> O(N)//实践中需求也不高string s2("hello world");s2.insert(0, "xxxx");cout << s2 << endl;s2.insert(0, 1, 'y');cout << s2 << endl;s2.insert(s2.begin(), 'y');cout << s2 << endl;s2.insert(s2.begin(), s1.begin(), s1.end());cout << s2 << endl;
}int main()
{test_string8();return 0;
}
void test_string9()
{string s1("hello world");cout << s1 << endl;//erase效率不高,慎用,和insert类似,要挪动数据s1.erase(0, 1);cout << s1 << endl;//s1.erase(5);s1.erase(5, 100);cout << s1 << endl;//replace效率不高,慎用,和insert类似,要挪动数据string s2("hello world");s2.replace(5, 1, "%20");cout << s2 << endl;string s3("hello world hello bit");for (size_t i = 0; i < s3.size(); ){if (' ' == s3[i]){s3.replace(i, 1, "%20");i += 3;}else{i++;}}cout << s3 << endl;string s4("hello world hello bit");string s5;for (auto ch : s4){if (ch != ' '){s5 += ch;}else{s5 += "%20";}}cout << s5 << endl;
}int main()
{test_string9();return 0;
}

我们来做几个题目:

  • 仅仅反转字母
    仅仅反转字母
class Solution
{
public:bool isLetter(char ch){if (ch >= 'a' && ch <= 'z'){return true;}if (ch >= 'A' && ch <= 'Z'){return true;}return false;}string reverseOnlyLetters(string s){if (s.empty()){return s;}size_t begin = 0, end = s.size() - 1;while (begin < end){while (begin < end && !isLetter(s[begin])){++begin;}while (begin < end && !isLetter(s[end])){--end;}swap(s[begin], s[end]);++begin;--end;}return s;}
};
  • 字符串中的第一个唯一字符
    字符串中的第一个唯一字符
 class Solution
{
public:int firstUniqChar(string s){int count[26] = { 0 };//统计次数for (auto ch : s){count[ch - 'a']++;}for (size_t i = 0; i < s.size(); ++i){if (1 == count[s[i] - 'a']){return i;}}return -1;}
};
  • 验证回文串
    验证回文串
class Solution
{
public:bool isLetterOrNumber(char ch){return (ch >= '0' && ch <= '9')|| (ch >= 'a' && ch <= 'z');}bool isPalindrome(string s){for (auto& ch : s){if (ch >= 'A' && ch <= 'Z'){ch += 32;}}int begin = 0, end = s.size() - 1;while (begin < end){while (begin < end && !isLetterOrNumber(s[begin])){++begin;}while (begin < end && !isLetterOrNumber(s[end])){--end;}if (s[begin] != s[end]){return false;}else{++begin;--end;}}return true;}
};
  • 字符串相加
    字符串相加

法一:

//时间复杂度:O(N^2) 因为头插的效率太低
class Solution
{
public:string addStrings(string num1, string num2){int end1 = num1.size() - 1;int end2 = num2.size() - 1;string str;int next = 0;//进位while (end1 >= 0 || end2 >= 0){int x1 = end1 >= 0 ? num1[end1--] - '0': 0;int x2 = end2 >= 0 ? num2[end2--] - '0': 0;int x = x1 + x2 + next;//处理进位next = x / 10;x = x % 10;//头插//str.insert(0, 1, '0' + x);str.insert(str.begin(), '0' + x);}if (1 == next){str.insert(str.begin(), '1');}return str;}
};

法二:

//时间复杂度:O(N)
class Solution
{
public:string addStrings(string num1, string num2){int end1 = num1.size() - 1;int end2 = num2.size() - 1;string str;int next = 0;//进位while (end1 >= 0 || end2 >= 0){int x1 = end1 >= 0 ? num1[end1--] - '0': 0;int x2 = end2 >= 0 ? num2[end2--] - '0': 0;int x = x1 + x2 + next;//处理进位next = x / 10;x = x % 10;//尾插str += ('0' + x);}if (1 == next){str += '1';}reverse(str.begin(), str.end());return str;}
};

  • string类对象的容量操作
void TestPushBack()
{string s;size_t sz = s.capacity();cout << "capacity changed: " << sz << '\n';cout << "making s grow:\n";for (int i = 0; i < 200; ++i){s.push_back('c');if (sz != s.capacity()){sz = s.capacity();cout << "capacity changed: " << sz << '\n';}}
}void test_string10()
{string s1("hello world hello bit");cout << s1.size() << endl;cout << s1.capacity() << endl;cout << s1.max_size() << endl;TestPushBack();string s1("111111111");string s2("11111111111111111111111111111111111111111111111111");
}int main()
{test_string10();return 0;
}

string类在不同环境下的对比

void TestPushBack()
{string s;//知道需要多少空间,提前开好s.reserve(200);size_t sz = s.capacity();cout << "capacity changed: " << sz << '\n';cout << "making s grow:\n";for (int i = 0; i < 200; ++i){s.push_back('c');if (sz != s.capacity()){sz = s.capacity();cout << "capacity changed: " << sz << '\n';}}
}void test_string10()
{	TestPushBack();string s1("111111111");string s2("11111111111111111111111111111111111111111111111111");cout << s1.capacity() << endl;s1.reserve(100);cout << s1.capacity() << endl;s1.reserve(20);cout << s1.capacity() << endl;
}int main()
{test_string10();return 0;
}

reserve

void test_string11()
{string s1;//s1.resize(5, '0');s1.resize(5);s1[4] = '3';s1[3] = '4';s1[2] = '5';s1[1] = '6';s1[0] = '7';//76543//插入(空间不够会扩容)string s2("hello world");s2.resize(20, 'x');//删除s2.resize(5);//s2[10];try{s2.at(10);}catch (const exception& e){cout << e.what() << endl;}
}int main()
{test_string11();return 0;
}

注:

  1. clear()只是将string中有效字符清空,不改变底层空间大小。(代码中没有演示)
  2. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变
  3. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小
  4. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。

  • string类的一些其他操作
#define _CRT_SECURE_NO_WARNINGS 1void test_string12()
{string file("test.cpp");FILE* fout = fopen(file.c_str(), "r");char ch = fgetc(fout);while (ch != EOF){cout << ch;ch = fgetc(fout);}
}int main()
{test_string12();return 0;
}
void test_string12()
{string file("string.cpp.zip");size_t pos = file.rfind('.');//string suffix = file.substr(pos, file.size() - pos);string suffix = file.substr(pos);cout << suffix << endl;
}int main()
{test_string12();return 0;
}
void test_string12()
{string url("https://gitee.com/ailiangshilove/cpp-class/blob/master/%E8%AF%BE%E4%BB%B6%E4%BB%A3%E7%A0%81/C++%E8%AF%BE%E4%BB%B6V6/string%E7%9A%84%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E5%8F%8A%E4%BD%BF%E7%94%A8/TestString.cpp");size_t pos1 = url.find(':');string url1 = url.substr(0, pos1 - 0);cout << url1 << endl;size_t pos2 = url.find('/', pos1 + 3);string url2 = url.substr(pos1 + 3, pos2 - (pos1 + 3));cout << url2 << endl;string url3 = url.substr(pos2 + 1);cout << url3 << endl;
}int main()
{test_string12();return 0;
}
void test_string13()
{string str("Please, replace the vowels in this sentence by asterisks.");size_t found = str.find_first_of("aeiou");while (found != string::npos){str[found] = '*';found = str.find_first_of("aeiou", found + 1);}cout << str << '\n';
}int main()
{test_string13();return 0;
}
void SplitFilename(const string& str)
{cout << "Splitting: " << str << '\n';size_t found = str.find_last_of("/\\");cout << " path: " << str.substr(0, found) << '\n';cout << " file: " << str.substr(found + 1) << '\n';
}int main()
{string str1("/usr/bin/man");string str2("c:\\windows\\winhelp.exe");SplitFilename(str1);SplitFilename(str2);return 0;
}
void test_string14()
{string s1 = "hello";string s2 = "world";string ret1 = s1 + s2;cout << ret1 << endl;string ret2 = s1 + "xxxxx";cout << ret2 << endl;string ret3 = "xxxxx" + s1;cout << ret3 << endl;//字典序比较cout << (s1 < s2) << endl;
}int main()
{test_string14();return 0;
}

一个题目:

  • 字符串最后一个单词的长度

字符串最后一个单词的长度

#include <iostream>
using namespace std;int main()
{string str;//默认规定空格或者换行是多个值之间分割//cin >> str;//获取一行中包含空格,不能用>>getline(cin, str);size_t pos = str.rfind(' ');cout << str.size() - (pos + 1) << endl;return 0;
}

  • 输入多行字符依次打印:
int main()
{//默认规定空格或者换行是多个值之间分割string str;//ctrl + z 就可以结束while (cin >> str){cout << str << endl;}return 0;
}
  • 字符串转整形,整形转字符串
int main()
{//atoi itoa//to_stringint x = 0, y = 0;cin >> x >> y;string str = to_string(x + y);cout << str << endl;int z = stoi(str);return 0;
}

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

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

相关文章

[数据结构]红黑树,详细图解插入

目录 一、红黑树的概念 二、红黑树的性质 三、红黑树节点的定义 四、红黑树的插入&#xff08;步骤&#xff09; 1.为什么新插入的节点必须给红色&#xff1f; 2、插入红色节点后&#xff0c;判定红黑树性质是否被破坏 五、插入出现连续红节点情况分析图解&#xff08;看…

java练习(28)

ps&#xff1a;练习来自力扣 给定一个二叉树&#xff0c;判断它是否是平衡二叉树 // 定义二叉树节点类 class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) { this.val val; }TreeNode(int val, TreeNode left, TreeNode right) {this.va…

Java并发编程6--重排序

重排序是指 编译 器和 处 理器 为 了 优 化程序性能而 对 指令序列 进 行重新排序的一种手段。 1.数据依赖性 如果两个操作 访问 同一个 变 量&#xff0c;且 这 两个操作中有一个 为 写操作&#xff0c;此 时这 两个操作之 间就存在数据 依赖性。 数据依赖的类型 上面 3 种情…

ElasticSearch映射分词

目录 弃用Type why 映射 查询 mapping of index 创建 index with mapping 添加 field with mapping 数据迁移 1.新建 一个 index with correct mapping 2.数据迁移 reindex data into that index 分词 POST _analyze 自定义词库 ik分词器 circuit_breaking_excep…

Python 面向对象的三大特征

前言&#xff1a;本篇讲解面向对象的三大特征&#xff08;封装&#xff0c;继承&#xff0c;多态&#xff09;&#xff0c;还有比较细致的&#xff08;类属性类方法&#xff0c;静态方法&#xff09;&#xff0c;分步骤讲解&#xff0c;比较适合理清楚三大特征的思路 面向对象的…

deepseek多列数据对比,联想到excel的高级筛选功能

目录 1 业务背景 ​2 deepseek提示词输入 ​3 联想分析 4 EXCEL高级搜索 1 业务背景 系统上线的时候经常会遇到一个问题&#xff0c;系统导入的数据和线下的EXCEL数据是否一致&#xff0c;如果不一致&#xff0c;如何快速找到差异值&#xff0c;原来脑海第一反应就是使用公…

俄罗斯方块游戏完整代码示例

以下是一个基于Cocos Creator引擎开发的俄罗斯方块游戏的完整代码示例。该游戏实现了俄罗斯方块的基本功能&#xff0c;并且代码整合在单个文件中&#xff0c;无需任何外部依赖&#xff0c;可以直接在浏览器中运行。 1. 创建Cocos Creator项目 首先&#xff0c;确保你已经安装了…

java后端开发day16--字符串(二)

&#xff08;以下内容全部来自上述课程&#xff09; 1.StringBuilder 因为StringBuilder是Java已经写好的类。 java在底层对他进行了一些特殊处理。 打印对象不是地址值而是属性值。 1.概述 StringBuilder可以看成是一个容器&#xff0c;创建之后里面的内容是可变的。 作用…

【AI实践】deepseek支持升级git

当前Windows 11 WSL的git是2.17&#xff0c;Android Studio提示需要升级到2.19版本 网上找到指导文章 安装git 2.19.2 cd /usr/src wget https://www.kernel.org/pub/software/scm/git/git-2.19.2.tar.gz tar xzf git-2.19.2.tar.gz cd git-2.19.2 make prefix/usr/l…

从零复现R1之路[3/3]:一文速览Open R1——对DeepSeek R1训练流程前两个阶段的复现(SFT和GRPO训练)

前言 根据R1的GitHub可知 类别开源内容未开源内容模型权重R1、R1-Zero 及蒸馏模型权重&#xff08;MIT 协议&#xff09;原始训练数据 未公开冷启动数据、RL 训练数据集或合成数据的具体内容&#xff0c;仅提供依赖的公开数据集名称&#xff08;如 AI-MO、NuminaMath-TIR&…

大语言模型简史:从Transformer(2017)到DeepSeek-R1(2025)的进化之路

2025年初&#xff0c;中国推出了具有开创性且高性价比的「大型语言模型」&#xff08;Large Language Model — LLM&#xff09;DeepSeek-R1&#xff0c;引发了AI的巨大变革。本文回顾了LLM的发展历程&#xff0c;起点是2017年革命性的Transformer架构&#xff0c;该架构通过「…

在线考试系统(代码+数据库+LW)

摘 要 使用旧方法对在线考试系统的信息进行系统化管理已经不再让人们信赖了&#xff0c;把现在的网络信息技术运用在在线考试系统的管理上面可以解决许多信息管理上面的难题&#xff0c;比如处理数据时间很长&#xff0c;数据存在错误不能及时纠正等问题。这次开发的在线考试…

2025百度快排技术分析:模拟点击与发包算法的背后原理

一晃做SEO已经15年了&#xff0c;2025年还有人问我如何做百度快速排名&#xff0c;我能给出的答案就是&#xff1a;做好内容的前提下&#xff0c;多刷刷吧&#xff01;百度的SEO排名算法一直是众多SEO从业者研究的重点&#xff0c;模拟算法、点击算法和发包算法是百度快速排名的…

【Spring+MyBatis】留言墙的实现

目录 1. 添加依赖 2. 配置数据库 2.1 创建数据库与数据表 2.2 创建与数据库对应的实体类 3. 后端代码 3.1 目录结构 3.2 MessageController类 3.3 MessageService类 3.4 MessageMapper接口 4. 前端代码 5. 单元测试 5.1 后端接口测试 5.2 使用前端页面测试 在Spri…

EtherNet/IP转Modbus TCP:新能源风电监控与分析实用案例

EtherNet/IP转Modbus TCP&#xff1a;新能源风电监控与分析实用案例 一、案例背景 在某新能源汽车电池生产线上&#xff0c;需要将采用EtherNet/IP协议的电池检测设备与采用ProfiNet协议的生产线控制系统进行集成&#xff0c;以实现对电池生产过程的全面监控和数据采集。 二、…

管理WSL实例 以及安装 Ubuntu 作为 WSL 子系统 流程

安装ubuntu wsl --install -d Ubuntu分类命令说明安装相关wsl --install在 Windows 10/11 上以管理员身份在 PowerShell 中运行此命令&#xff0c;可安装 WSLwsl --install -d <distribution name>在 PowerShell 中使用此命令安装特定版本的 Linux 发行版&#xff0c;如…

Spring框架中都用到了哪些设计模式?

大家好&#xff0c;我是锋哥。今天分享关于【Spring框架中都用到了哪些设计模式&#xff1f;】面试题。希望对大家有帮助&#xff1b; Spring框架中都用到了哪些设计模式&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring框架中使用了大量的设计模…

最新VS code配置C/C++环境(tasks.json, launch.json,c_cpp_properties.json)及运行多个文件、配置Cmake

目录 一、VScode配置C/C环境&#xff0c;需设置tasks.json, launch.json文件 二、安装C/C扩展&#xff0c;配置tasks.json、launch.json、c_cpp_properties.json文件 (1)安装c/c扩展 (2)配置tasks.json文件 (3)配置launch.json文件 (4)配置中的参数(属性)说明 (5)运行程序(运行…

Java零基础入门笔记:(3)程序控制

前言 本笔记是学习狂神的java教程&#xff0c;建议配合视频&#xff0c;学习体验更佳。 【狂神说Java】Java零基础学习视频通俗易懂_哔哩哔哩_bilibili Scanner对象 之前我们学的基本语法中我们并没有实现程序和人的交互&#xff0c;但是Java给我们提供了这样一个工具类&…

Spring Boot 原理分析

spring-boot.version&#xff1a;2.4.3.RELEASE Spring Boot 依赖管理 spring-boot-starter-parent 配置文件管理 <resources> <resource> <directory>${basedir}/src/main/resources</directory> <filtering>true&l…