【C++ 学习 ⑨】- 万字详解 string 类(上)

news2024/12/23 23:07:36

目录

一、为什么学习 string 类?

二、标准库中的 string 类

三、C++ STL容器是什么?

四、string 类的成员函数

4.1 - 构造函数

4.2 - 赋值运算符重载

4.3 - 容量操作

4.4 - 遍历及访问操作

4.4.1 - operator[] 和 at

4.4.2 - 迭代器

4.5 - 修改操作

4.6 - 字符串操作

五、string 类的非成员函数重载

六、C++ STL 迭代器详解

6.1 - 迭代器的类别

6.2 - 迭代器的定义方式



一、为什么学习 string 类?

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


二、标准库中的 string 类

字符串是表示字符序列的对象。

标准 string 类通过类似于标准字节容器(standard container of bytes)的接口为此类对象提供支持,但添加了专门设计用于处理单字节字符串的功能。

string 类是 basic_string 类模板的一个实例化,该模板使用 char(即字节)作为其 character type,以及使用默认的 char_traits and allocator type(有关模板的详细信息,请参阅 basic_string)。

typedef basic_string<char> string;

请注意,此类独立于所使用的编码来处理字节:如果用于处理多字节或可变长度字符(如 UTF-8)的序列,则此类的所有成员(如 length 或 size)及其迭代器仍将以字节(而不是实际编码字符)为单位运行。


三、C++ STL容器是什么?

简单理解,容器就是一些类模板的集合,但和普通类模板不同的是,容器中封装的是组织数据的方法(也就是数据结构)。STL 提供有 3 类标准容器,分别是序列容器、排序容器和哈希容器,其中后两类容器有时也统称为关联容器。它们各自的含义如下表所示:

容器种类功能
序列容器主要包括 vector 向量容器、list 列表容器以及 deque 双端队列容器。之所以被称为序列容器,是因为元素在容器中的位置同元素的值无关,即容器不是排序的。将元素插入容器时,指定在什么位置,元素就会位于什么位置。
排序容器包括 set 集合容器、multiset 多重集合容器、map 映射容器以及 multimap 多重映射容器。排序容器中的元素默认是由小到大排序好的,即便是插入元素,元素也会插入到适当位置。所以关联容器在查找时具有非常好的性能。
哈希容器C++ 11 新加入 4 种关联容器,分别是 unordered_set 哈希集合、unordered_multiset 哈希多重集合、unordered_map 哈希映射以及 unordered_multimap 哈希多重映射。和排序容器不同,哈希容器中的元素是未排序的,元素的位置由哈希函数确定。

注意,由于哈希容器直到 C++ 11 才被正式纳入 C++ 标准程序库,而在此之前,"民间" 流传着 hash_set、hash_multiset、hash_map、hash_multimap 版本,不过这些版本只能在某些支持 C++ 11 的编译器下使用(例如 VS),有些编译器(例如 GCC/G++) 是不支持的

另外,以上 3 类容器的存储方式完全不同,因此使用不同容器完成相同操作的效率也大不相同。所以在实际使用时,要善于根据想实现的功能,选择合适的容器。

另外,string 类属于标准库,不属于 STL,但它与 STL 容器有很多相似的操作,因此在正式学习 STL 之前,首先学习 string 类


四、string 类的成员函数

4.1 - 构造函数

      default (1) string();
         copy (2) string(const string& str);
    substring (3) string(const string& str, size_t pos, size_t len = npos);
from c-string (4) string(const char* s);
  from buffer (5) string(const char* s, size_t n);
         fill (6) string(size_t n, char c);

说明

  1. 默认构造函数(default constructor):构造一个空的 string 类对象,即空字符串。

  2. 拷贝构造函数(copy constructor)。

  3. 拷贝 str 的一部分,这部分从字符位置 pos 开始并跨越 len 个字符(如果 str 太短或者 len 为 string::npos,则拷贝到 str 的末尾)。

    npos 是公共静态成员常量(public static member constant),值为 size_t 类型数据的最大可能值。

    static const size_t npos = -1;
  4. 拷贝 s 指向的以 \0 结尾的字符串。

  5. s 指向的字符数组中拷贝前 n 个字符。

  6. 用 n 个 c 字符填充 string 类对象。

示例

#include <iostream>
#include <string>
using namespace std;
​
int main()
{
    string s1;
    cout << s1 << endl;  // 空
​
    string s2("hello world");
    string s3("hello world", 5);
    cout << s2 << endl;  // hello world
    cout << s3 << endl;  // hello
​
    string s4(s2);
    string s5(s2, 6, 3);
    string s6(s2, 6);
    cout << s4 << endl;  // hello world
    cout << s5 << endl;  // wor
    cout << s6 << endl;  // world
    cout << string::npos << endl;  // 4294967295(2^32 - 1)
​
    string s7(10, '*');
    cout << s7 << endl;  // **********
    return 0;
}

4.2 - 赋值运算符重载

   string (1) string& operator=(const string& str);
 c-string (2) string& operator=(const char* s);
character (3) string& operator=(char c);

示例

#include <iostream>
#include <string>
using namespace std;
​
int main()
{
    string s1;
    string s2("hello world");
​
    s1 = s2;
    cout << s1 << endl;  // hello world
​
    s1 = "你好,世界";
    cout << s1 << endl;  // 你好,世界
​
    s1 = 'A';
    cout << s1 << endl;  // A
    return 0;
}

4.3 - 容量操作

length:

size_t length() const;

返回字符串有效字符长度。

size:

size_t size() const;

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

empty:

bool empty() const;

如果字符串的长度为 0,返回 true,否则返回 false。

max_size:

size_t max_size() const;

返回字符串可以达到的最大长度。

注意:不同的编译器以及不同的版本实现可能不一样

capacity:

size_t capacity() const;

返回当前为字符串分配的存储空间的大小。

注意:和 max_size() 一样,对于 capacity(),不同的编译器以及不同的版本实现可能也不一样

clear:

void clear();

清空有效字符。

注意:clear() 不改变底层空间的大小

reserve:

void reserve(size_t n = 0);

如果 n 大于当前的字符串容量(capacity),则该函数会让容量增加到 n(或更大)

在其他所有情况下,缩小容量被视为非约束性请求(a non-blinding request):容器实现可以自由优化,否则,字符串的容量大于 n

该函数不会对字符串的长度造成任何影响,并且也不会改变字符串的内容

resize:

void resize(size_t n);
void resize(size_t n, char c);

如果 n 大于当前字符串长度,则在末尾插入 '\0' 或字符 c,在此过程中,可能会改变底层容量的大小

如果 n 小于当前字符串长度,则删除前 n 个字符以外的字符

示例

#include <iostream>
#include <string>
using namespace std;
​
// 测试环境:VS2019
int main()
{
    string s("hello world");
    cout << s.length() << endl;  // 11
    cout << s.size() << endl;  // 11
    cout << s.empty() << endl;  // 0
    cout << s.max_size() << endl;  // 2147483647
    cout << s.capacity() << endl;  // 15
​
    s.clear();
    cout << s.size() << endl;  // 0
    cout << s.capacity() << endl;  // 15
​
    s = "hello world";
    // n > capacity
    s.reserve(20);
    cout << s.capacity() << endl;  // 31
    // n < capacity
    s.reserve(5);
    cout << s.capacity() << endl;  // 31
    s.clear();
    s.reserve(5);
    cout << s.capacity() << endl;  // 15
​
    s = "hello world";
    // n > size
    s.resize(20, 'x');
    cout << s << endl;  // hello worldxxxxxxxxx
    cout << s.size() << endl;  // 20
    cout << s.capacity() << endl;  // 31
    // n < size
    s.resize(5);
    cout << s << endl;  // hello
    cout << s.size() << endl;  // 5
    cout << s.capacity() << endl;  // 31
    return 0;
}

4.4 - 遍历及访问操作

4.4.1 - operator[] 和 at

operator[]:

      char& operator[](size_t pos);
const char& operator[](size_t pos) const;

at:

      char& at(size_t pos);
const char& at(size_t pos) const;

operator[]() 和 at() 的功能类似,都是返回字符串中 pos 位置处的字符的引用

不同之处在于,当 pos 不是合法位置时,operator[]() 会直接报错,而 at() 会抛出 out_of_range 异常

示例一

#include <iostream>
#include <string>
using namespace std;
​
int main()
{
    string s("01234");
    for (size_t i = 0; i < s.size(); ++i)
    {
        // s[i] += 5;
        // cout << s[i];
        s.at(i) += 5;
        cout << s.at(i);
    }
    // 56789
    cout << endl;
    return 0;
}

示例二

#include <iostream>
#include <string>
using namespace std;
​
int main()
{
    try 
    {
        string s("01234");
        // s[10] = 'x';  // 直接报错
        s.at(10) = 'x';
    }
    catch (const exception& e)
    {
        cout << e.what() << endl;  // invalid string position
    }
    return 0;
}

4.4.2 - 迭代器

begin:

      iterator begin();
const_iterator begin() const;

返回指向字符串第一个字符的迭代器。

end:

      iterator end();
const_iterator end() const;

返回指向字符串最后一个字符的下一个位置的迭代器。

示例一

#include <iostream>
#include <string>
using namespace std;
​
int main()
{
    string s1("01234");
    for (string::iterator it1 = s1.begin(); it1 != s1.end(); ++it1)
    {
        *it1 += 5;  // 写
        cout << *it1;  // 读
    }
    // 56789
    cout << endl;
​
    const string s2("01234");
    for (string::const_iterator it2 = s2.begin(); it2 != s2.end(); ++it2)
    {
        // 必须使用 const_iterator,否则权限就放大了
        // *it2 += 5;  // 不能写
        cout << *it2;  // 只能读
    }
    // 01234
    cout << endl;
    return 0;
}
  1. 为了方便,可以使用 auto 关键字

    for (auto it1 = s1.begin(); it1 != s1.end(); ++it1) { ... }
    for (auto it2 = s2.begin(); it2 != s2.end(); ++it2) { ... }
  2. 基于范围的 for 循环的内部实现机制还是依赖于迭代器的相关实现

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main()
    {
    	string s("01234");
    	for (char& e : s)  // 或者 for (auto& e : s) { ... }
    	{
    		e += 5;
    		cout << e;
    	}
    	// 56789
    	cout << endl;
    	return 0;
    }
     

rbegin:

      reverse_iterator rbegin() const;
const_reverse_iterator rbegin() const;

返回指向字符串最后一个字符的反向迭代器。

rend:

      reverse_iterator rend() const;
const_reverse_iterator rend() const;

返回指向字符串第一个字符的前一个位置的反向迭代器。

示例二

#include <iostream>
#include <string>
using namespace std;
​
int main()
{
    string s("01234");
    for (auto it = s.rbegin(); it != s.rend(); ++it)
    {
        *it += 5;
        cout << *it;
    }
    // 98765
    cout << endl;
    return 0;
}

4.5 - 修改操作

operator+= :

   string (1) string& operator+=(const string& str);
 c-string (2) string& operator+=(const char* s);
character (3) string& operator+=(char c);

append :

   string (1) string& append(const string& str);
substring (2) string& append(const string& str, size_t subpos, size_t sublen);
 c-string (3) string& append(const char* s);
   buffer (4) string& append(const char* s, size_t n);
     fill (5) string& append(size_t n, char c);

示例一

#include <iostream>
#include <string>
using namespace std;
​
int main()
{
    string s1;
    string s2("hello world");
    s1 += s2;
    cout << s1 << endl;  // hello world
    s1 += "xxx";
    cout << s1 << endl;  // hello worldxxx
    s1 += 'y';
    cout << s1 << endl;  // hello worldxxxy
​
    s1.clear();
    s1.append(s2);
    cout << s1 << endl;  // hello world
    s1.append(s2, 6, 3);
    cout << s1 << endl;  // hello worldwor
    s1.append("xxx");
    cout << s1 << endl;  // hello worldworxxx
    s1.append("yyy", 1);
    cout << s1 << endl;  // hello worldworxxxy
    s1.append(2, 'z');
    cout << s1 << endl;  // hello worldworxxxyzz
    return 0;
}

insert:

           string (1) string& insert(size_t pos, const string& str);
        substring (2) string& insert(size_t pos, const string& str, size_t subpos, size_t sublen);
         c-string (3) string& insert(size_t pos, const char* s);
           buffer (4) string& insert(size_t pos, const char* s, size_t);
             fill (5) string& insert(size_t pos, size_t n, char c);
                         void insert(iterator p, size_t n, char c);
single character (6) iterator insert(iterator p, char c);

erase:

 sequence (1)  string& erase(size_t pos = 0, size_t len = npos);
character (2) iterator erase(iterator p);
    range (3) iterator erase(iterator first, iterator last);

示例二

int main()
{
    string s1("xxxxxyyyyy");
    string s2("hello world");
    // cout << s1.insert(5, s2) << endl;  // xxxxxhello worldyyyyy
    // cout << s1.insert(5, s2, 6, 5) << endl;  // xxxxxworldyyyyy
    // cout << s1.insert(5, "zzzzz") << endl;  // xxxxxzzzzzyyyyy
    // cout << s1.insert(5, "zzzzz", 3) << endl;  // xxxxxzzzyyyyy
    // cout << s1.insert(5, 5, '*') << endl;  // xxxxx*****yyyyy
    /* 
       s1.insert(s1.begin() + 5, 5, '*');
       cout << s1 << endl;  // xxxxx*****yyyyy
    */
    s1.insert(s1.begin() + 5, 'Z');
    cout << s1 << endl;  // xxxxxZyyyyy
    
    
    // cout << s1.erase(5, 1) << endl;  // xxxxxyyyyy
    /*
       s1.erase(s1.begin() + 5);
       cout << s1 << endl;  // xxxxxyyyyy
    */
    s1.erase(s1.begin() + 5, s1.end());  // [first, last)
    cout << s1 << endl;  // 
    return 0;
}

4.6 - 字符串操作

c_str:

const char* c_str() const;

返回一个指向字符数组的指针,该数组包括构成 string 类对象的字符序列,以及在末尾符加的 '\0'

find:

   string (1) size_t find(const string& str, size_t pos = 0) const;
 c-string (2) size_t find(const char* s, size_t pos = 0) const;
   buffer (3) size_t find(const char* s, size_t pos, size_t n) const;
character (4) size_t find(char c, size_t pos = 0) const;

rfind:

   string (1) size_t rfind(const string& str, size_t pos = npos) const;
 c-string (2) size_t rfind(const char* s, size_t pos = npos) const;
   buffer (3) size_t rfind(const char* s, size_t pos, size_t n) const;
character (4) size_t rfind(char c, size_t pos = npos) const;

substr:

string substr(size_t pos = 0, size_t len = npos) const;

示例

#include <iostream>
#include <string>
using namespace std;
​
// URL(Uniform Resource Locator):全球资源定位器
// protocol:协议
// domain name:域名
// URI(Uniform Resource Identifier):统一资源标识符
​
int main()
{
    string url("https://legacy.cplusplus.com/reference/string/string/");
​
    size_t begin1 = 0;
    size_t end1 = url.find("://", begin1);
    string protocol;
    if (end1 != string::npos)
    {
        protocol = url.substr(begin1, end1 - begin1);
        cout << protocol << endl;  // https
    }
​
    size_t begin2 = end1 + 3;
    size_t end2 = url.find('/', begin2);
    string domainName, uri;
    if (end2 != string::npos)
    {
        domainName = url.substr(begin2, end2 - begin2);
        uri = url.substr(end2 + 1);
        cout << domainName << endl;  // legacy.cplusplus.com
        cout << uri << endl;  // reference/string/string/
    }
​
    return 0;
}


五、string 类的非成员函数重载

函数名称功能说明
operator+Concatenate strings(尽量少用,因为是传值返回)
relational operatorsRelational operators for string
swapExchanges the value of two strings
operator>>Extract string from stream
operator<<Insert string into stream
getlineGet line from stream into string


六、C++ STL 迭代器详解

无论是序列容器还是关联容器,最常做的操作无疑是遍历容器中存储的元素,而实现此操作,多数情况会选用 "迭代器(iterator)" 来实现。那么,迭代器到底是什么呢?

我们知道,尽管不同容器的内部结构各异,但它们本质上都是用来存储大量数据的,换句话说,都是一串能存储多个数据的存储单元。因此,诸如数据的排序、查找、求和等需要对数据进行遍历的操作方法应该是类似的

既然类似,完全可以利用泛型技术,将它们设计成适用所有容器的通用算法,从而将容器和算法分离开。但实现此目的需要有一个类似中介的装置,它除了要具有对容器进行遍历读写数据的能力之外,还要能对外隐藏容器的内部差异,从而以统一的界面向算法传送数据。这是泛型思维发展的必然结果,于是迭代器就产生了

简单来讲,迭代器和指针非常类似,它可以是需要的任意类型,通过迭代器可以指向容器中的某个元素,如果需要,还可以对元素进行读/写操作

6.1 - 迭代器的类别

STL 为每一种标准容器定义了一种迭代器类型,这意味着,不同容器的迭代器不同,其功能强弱也有所不同。

容器的迭代器的功能强弱,决定了该容器是否支持 STL 中的某种算法

常用的迭代器按功能强弱分为输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机访问迭代器 5 种

输入迭代器和输出迭代器比较特殊,它们不是把数组或容器当作操作对象,而是把输入流/输出流作为操作对象。有关这 2 个迭代器,我们会在后续的学习中做详细介绍。

  1. 前向迭代器(forward iterator)

    假设 p 是一个前向迭代器,则 p 支持 ++pp++*p 操作,还可以被复制或赋值,可以用 == 和 != 运算符进行比较。此外,两个正向迭代器还可以相互赋值。

  2. 双向迭代器(bidirectional iterator)

    双向迭代器具有前向迭代器的全部功能,除此之外,假设 p 是一个双向迭代器,则还可以进行 --p 或者 p-- 操作(即一次向后移动一个位置)。

  3. 随机访问迭代器(random access iterator)

    随机访问迭代器具有双向迭代器的全部功能,除此之外,假设 p 是一个随机访问迭代器,i 是一个整型变量或常量,则 p 还支持以下操作:

    • p += i; 即使得 p 往后移动 i 个元素。

    • p -= i; 即使得 p 往前移动 i 个元素。

    • p + i; 即返回 p 后面第 i 个元素的迭代器。

    • p - i; 即返回 p 前面第 i 个元素的迭代器。

    • p[i]; 即返回 p 后面第 i 个元素的引用。

    此外,两个随机访问迭代器 p1、p2 还可以用 <、>、<=、>= 运算符进行比较。另外,表达式 p2 - p1 也是有定义的,其返回值表示 p2 所指元素和 p1 所指元素的序号之差(也可以说是 p2 和 p1 之间的元素减一)。

C++ 11 标准中不同容器指定使用的迭代器类型

容器对应的迭代器类型
array随机访问迭代器
vector随机访问迭代器
deque随机访问迭代器
list双向迭代器
set/ multiset双向迭代器
map/ multiset双向迭代器
forward_list前向迭代器
unordered_map/ unordered_multimap前向迭代器
unordered_set/ unordered_multiset前向迭代器
stack不支持迭代器
queue不支持迭代器

注意,容器适配器 stack 和 queue 没有迭代器,它们包含有一些成员函数,可以用来对元素进行访问

6.2 - 迭代器的定义方式

尽管不同容器对应着不同类别的迭代器,但这些迭代器有着较为统一的定义方式,具体分为 4 种,如下表所示:

迭代器定义方式具体格式
正向迭代器容器类名::iterator 迭代器名;
常量正向迭代器容器类名::const_iterator 迭代器名;
反向迭代器容器类名::reverse_iterator 迭代器名;
常量反向迭代器容器类名::const_reverse_iterator 迭代器名;

反向迭代器全称为 "反向迭代器适配器",在后续学习中会做详细讲解,这里只需要知道其用法即可

通过定义以上几种迭代器,就可以读取它指向的元素,*迭代器名 就表示迭代器指向的元素。其中,常量迭代器和非常量迭代器的分别在于,通过非常量迭代器还能修改其指向的元素。另外,反向迭代器和正向迭代器的区别在于:

  • 对正向迭代器进行 ++ 操作时,迭代器会指向容器中的后一个元素;

  • 而对反向迭代器进行 ++ 操作时,迭代器会指向容器中的前一个元素。

注意,以上 4 种定义迭代器的方式,并不是每个容器都适用。有一部分容器同时支持以上 4 种方式,比如 array、deque、vector;而有些容器只支持其中部分的定义方式,例如 forward_list 容器只支持定义正向迭代器,不支持定义反向迭代器。

具体容器支持定义迭代器的方式,讲具体容器时会详细说明。另外,读者也可以通过 C++ STL 标准手册,查询具体容器迭代器支持的定义方式。

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

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

相关文章

Node.js 使用踩坑

重装电脑后&#xff0c;重装node.js 出现一个问题&#xff1a; npm install 会报错 按提示操作后 而npm run serve 会报xlsx和echart的错误&#xff0c;提示引用不对之类的&#xff0c;但是公司项目固定的&#xff0c;不可以随便改&#xff0c;而且之前是没问题的。 此时需要找…

华为OD机试真题B卷 Java 实现【数组拼接】,附详细解题思路

一、题目描述 现在有多组整数数组&#xff0c;需要将它们合并成一个新的数组。 合并规则&#xff0c;从每个数组里按顺序取出固定长度的内容合并到新的数组中&#xff0c;取完的内容会删除掉&#xff0c;如果该行不足固定长度或者已经为空&#xff0c;则直接取出剩余部分的内…

Anaconda教程,Python版本控制

Anaconda教程,Python版本控制 文章目录 Anaconda教程,Python版本控制1&#xff1a;Anaconda安装1.1&#xff1a;Windows1.2&#xff1a;Linux1.3&#xff1a;MacOS 2&#xff1a;Anaconda使用2.1&#xff1a;创建一个新的环境2.2&#xff1a;安装 Python 包2.3&#xff1a;激活…

hash模式下路由跳转页面不刷新

mode为hash时&#xff0c;纯粹页面&#xff0c;路由跳转过之后跳转上一级重复路由页面不会重新渲染 举个例子&#xff1a;当我在注册页面->注册状态页面->注册页面&#xff0c;在这个期间我从注册状态页面进行缓存的数据想要在注册页面使用&#xff0c;然而注册页面不会…

【YOLO系列】YOLO v5(网络结构图+代码)

文章目录 推理转换onnx网络架构SPP VS SPPFAutoAnchorLoss 参考 【YOLO系列】YOLO v3&#xff08;网络结构图代码&#xff09; 【YOLO 系列】YOLO v4-v5先验知识 【YOLO系列】YOLO v4&#xff08;网络结构图代码&#xff09; 我是在自己笔记本上配置的YOLO v5环境。首先&#x…

饼状图使用属性时,使用驼峰命名法

饼状图是使用D3.js等JavaScript库来绘制的&#xff0c;而JavaScript中的属性名通常采用驼峰式命名法&#xff0c;即第一个单词的首字母小写&#xff0c;后面单词的首字母大写&#xff0c;例如fontSize、fontWeight等。而CSS中的属性名采用连字符命名法&#xff0c;即单词之间用…

Top 5 Best Open Source Projects on GitHub 2023

这里介绍Github上 5 个增长最快的开源项目&#xff0c;它们为原有的解决方案提供了更加具有成本效益的替代方案&#xff0c;并为开发者、数据分析师和企业提供了高可用的工具产品。利用开源的优势&#xff0c;这5个项目拓展了强大而有效的解决方案&#xff0c;是值得收藏、分享…

比ureport好用的报表系统-VeryReport报表系统

随着数据时代的到来&#xff0c;数据成为企业管理和决策的重要依据。然而&#xff0c;在处理海量数据的同时&#xff0c;如何快速准确地生成各种形式的报表却成为了一个痛点。手工制作报表费时费力、容易出错&#xff1b;而传统的报表工具又复杂难用&#xff0c;无法满足不同用…

基于jsp+mysql+Spring+mybatis+Springboot的SpringBoot婚纱影楼摄影预约网站

运行环境: 最好是java jdk 1.8&#xff0c;我在这个平台上运行的。其他版本理论上也可以。 IDE环境&#xff1a; Eclipse,Myeclipse,IDEA或者Spring Tool Suite都可以&#xff0c;如果编译器的版本太低&#xff0c;需要升级下编译器&#xff0c;不要弄太低的版本 tomcat服务器环…

Linux下快速创建大文件的4种方法总结

1、使用 dd 命令创建大文件 dd 命令用于复制和转换文件&#xff0c;它最常见的用途是创建实时 Linux USB。dd 命令是实际写入硬盘&#xff0c;文件产生的速度取决于硬盘的读写速度&#xff0c;根据文件的大小&#xff0c;该命令将需要一些时间才能完成。 假设我们要创建一个名…

SAP从入门到放弃系列之CRP-part2

标准的生产处理流程如下&#xff1a; 在标准的流程里&#xff0c;MRP为无限产能方式&#xff0c;所以在MRP或者MPS之后&#xff0c;需要进行CRP计算&#xff0c;然后调整。 测试数据准备&#xff1a; 1、参考复制part1文章中的ZW01CRP工作中心复制到新的ZW01CRP2。 2、为物…

springboot 连接 kafka集群(kafka版本 2.13-3.4.0)

springboot 连接 kafka集群 一、环境搭建1.1 springboot 环境1.2 kafka 依赖 二、 kafka 配置类2.1 发布者2.1.1 配置2.1.2 构建发布者类2.1.3 发布消息 2.2 消费者2.2.1 配置2.2.2 构建消费者类2.2.3 进行消息消费 一、环境搭建 1.1 springboot 环境 JDK 11 Maven 3.8.x spr…

SpringCloud Alibaba Nacos--下

SpringCloud Alibaba Nacos-下 Nacos 配置中心实例 示意图 在Nacos Server 加入配置 进入到Nacos Server加入配置&#xff0c; 特别提醒: 文件后缀.yaml 别忘了. Data ID: e-commerce-nacos-config-client-dev.yaml 创建Nacos 配置客户端模块e-commerce-nacos-config-client…

kafka集群报错找不到broker

一、问题描述 某次用户反馈&#xff0c;kafka消费这边消息失败&#xff0c;报错消费者被踢出消费组或broker状态异常无法连接&#xff0c;后实际验证端口确实不通 现场测试验证&#xff0c;报错&#xff1a;报错&#xff1a;Failed to find brokers to send ListGroups……fi…

实战干货,pytest自动化测试-Git中的测试用例运行(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 我们每天写完自动…

httprunner 2.x的基本使用(二)

上一章&#xff1a; httprunner 2.x介绍与使用_做测试的喵酱的博客-CSDN博客 下一章&#xff1a; 一、 api 文件夹&#xff08;没有任何数据依赖的场景&#xff09; api 文件夹&#xff1a;执行接口case的最小单元。如果一个接口case&#xff0c;没有任何数据依赖&#xff0…

虚拟ECU实践:汽车发动机控制器仿真

虚拟化技术使得在Windows PC上对汽车ECU&#xff08;Electronic Control Unit&#xff0c;电子控制器单元&#xff09;进行闭环仿真成为可能&#xff0c;能有效改善ECU开发过程。一些开发任务得以从道路、测试平台和HIL&#xff08;Hardware in the Loop&#xff0c;硬件在环&a…

Python入门教程+项目实战-13.3节-集合的快速查找

目录 13.3.1 键的输出顺序 13.4.2 键的数据类型 13.4.3 集合的快速查找 13.4.4 知识要点 13.4.5 系统学习python 13.3.1 键的输出顺序 集合类型的底层实现基于哈希表&#xff0c;键的输出顺序取决于键在哈希表中的存储顺序。 对哈希表结构不是很熟悉的同学&#xff0c;可…

【DBA生存之四大守则---读书笔记】

&#x1f448;【上一篇】 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 【下一篇】&#x1f449; &#x1f53b;《Oracle 数据库性能优化》一书的序言中提到: 兴趣勤奋坚持方法成功 很遗憾我不能给以上公式画上“”&#xff0c;但是无…

Coggle 30 Days of ML 打卡任务一

Coggle 30 Days of ML 打卡任务一 任务一&#xff1a;两个赛题数据可视化 难度/分值&#xff1a;低/1 打卡内容&#xff1a; 参赛选手名称&#xff1a;AppleDoctor完成日期&#xff1a;2023.6.6任务完成情况&#xff1a; 使用的编程语言&#xff1a;Python实现的功能&#…