【C++】迭代器

内容来自《C++ Primer(第5版)》9.2.1 迭代器、9.2.3 begin和end成员、9.3.6 容器操作可能使迭代器失效、10.4.3 反向迭代器


目录

1. 迭代器

1.1 迭代器范围

1.2 使用左闭合范围蕴含的编程假定

2. begin和end成员

3. 容器操作可能使迭代器失效

3.1 编写改变容器的循环程序

3.2 不要保存end返回的迭代器

4. 反向迭代器

4.1 反向迭代器需要递减运算符

4.2 反向迭代器和其他迭代器间的关系


1. 迭代器

与容器一样,迭代器有着公共的接口:如果一个迭代器提供某个操作,那么所有提供相同操作的迭代器对这个操作的实现方式都是相同的。例如,标准容器类型上的所有迭代器都允许我们访问容器中的元素,而所有迭代器都是通过解引用运算符来实现这个操作的。类似的,标准库容器的所有迭代器都定义了递增运算符,从当前元素移动到下一个元素。

表1列出了容器迭代器支持的所有操作,其中有一个例外不符合公共接口特点——forward_list迭代器不支持递减运算符(--)。表2列出了迭代器支持的算术运算,这些运算只能应用于string、vector、deque和array的迭代器。我们不能将它们用于其他任何容器类型的迭代器。

表1 迭代器的运算符
*iter返回迭代器iter所指元素的引用
iter->mem解引用iter并获取该元素的名为mem的成员,等价于(*iter) .mem
++iter令iter指示容器中的下一个元素
--iter令iter指示容器中的上一个元素
iter1 == iter2判断两个迭代器是否相等(不相等),如果两个迭代器指示的是同一个元素或者它们是同一个容器的尾后迭代器,则相等;反之,不相等
iter1 != iter2
表2 迭代器支持的运算
iter + n迭代器加上一个整数值仍得一个迭代器,迭代器指示的新位置与原来相比向前移动了若干个元素。结果迭代器或者指示容器内的一个元素,或者指示容器尾元素的下一位置
iter - n迭代器减去一个整数值仍得一个迭代器,迭代器指示的新位置与原来相比向后移动了若干个元素。结果迭代器或者指示容器内的一个元素,或者指示容器尾元素的下一位置
iter1 += n迭代器加法的复合赋值语句,将iter1加n的结果赋给iter1
iter1 -= n迭代器减法的复合赋值语句,将iter1减n的结果赋给iter1
iter1 - iter2两个迭代器相减的结果是它们之间的距离,也就是说,将运算符右侧的迭代器向前移动差值个元素后将得到左侧的迭代器。参与运算的两个迭代器必须指向的是同一个容器中的元素或者尾元素的下一位置
>、>=、<、<=迭代器的关系运算符,如果某迭代器指向的容器位置在另一个迭代器所指位置之前,则说前者小于后者。参与运算的两个迭代器必须指向的是同一个容器中的元素或者尾元素的下一位置

1.1 迭代器范围

Note

迭代器范围的概念是标准库的基础。

一个迭代器范围(iterator range)由一对迭代器表示,两个迭代器分别指向同一个容器中的元素或者是尾元素之后的位置(one past the last element)。这两个迭代器通常被称为begin和end,或者是first和last(可能有些误导),它们标记了容器中元素的一个范围。

虽然第二个迭代器常常被称为last,但这种叫法有些误导,因为第二个迭代器从来都不会指向范围中的最后一个元素,而是指向尾元素之后的位置。迭代器范围中的元素包含first所表示的元素以及从first开始直至last(但不包含last)之间的所有元素。

这种元素范围被称为左闭合区间(left-inclusive interval),其标准数学描述为

[begin, end)

表示范围自begin开始,于end之前结束。迭代器begin和end必须指向相同的容器。end可以与begin指向相同的位置,但不能指向begin之前的位置。

对构成范围的迭代器的要求

如果满足如下条件,两个迭代器begin和end构成一个迭代器范围:

  • 它们指向同一个容器中的元素,或者是容器最后一个元素之后的位置,且
  • 我们可以通过反复递增begin来到达end。换句话说,end不在begin之前。

WARNING

编译器不会强制这些要求。确保程序符合这些约定是程序员的责任。

1.2 使用左闭合范围蕴含的编程假定

标准库使用左闭合范围是因为这种范围有三种方便的性质。假定begin和end构成一个合法的迭代器范围,则

  • 如果begin与end相等,则范围为空
  • 如果begin与end不等,则范围至少包含一个元素,且 begin指向该范围中的第一个元素
  • 我们可以对begin递增若干次,使得begin==end

这些性质意味着我们可以像下面的代码一样用一个循环来处理一个元素范围,而这是安全的:

while (begin != end) {
    *begin = val;//正确:范围非空,因此begin指向一个元素
    ++begin;     //移动迭代器,获取下一个元素
}

给定构成一个合法范围的迭代器begin和end,若 begin==end,则范围为空。在此情况下,我们应该退出循环。如果范围不为空,begin指向此非空范围的一个元素。因此,在while循环体中,可以安全地解引用begin,因为begin必然指向一个元素。最后,由于每次循环对begin递增一次,我们确定循环最终会结束。

2. begin和end成员

begin和end操作生成指向容器中第一个元素和尾元素之后位置的迭代器。这两个迭代器最常见的用途是形成一个包含容器中所有元素的迭代器范围。

表3 获取迭代器操作
beginend
rbeginrend
cbegincend
crbegincrend

如表3所示,begin和end有多个版本:带r的版本返回反向迭代器;以c开头的版本则返回const迭代器:

list<string> a = { "Milton","Shakespeare","Austen" };
auto itl = a.begin();  //list<string>::iterator
auto it2 = a.rbegin(); //list<string>::reverse_iterator
auto it3 = a.cbegin(); //list<string>::const_iterator
auto it4 = a.crbegin();//list<string>::const_reverse_iterator

不以c开头的函数都是被重载过的。也就是说,实际上有两个名为begin的成员。一个是const成员,返回容器的const_iterator类型。另一个是非常量成员,返回容器的iterator类型。rbegin、end和rend的情况类似。当我们对一个非常量对象调用这些成员时,得到的是返回iterator的版本。只有在对一个const对象调用这些函数时,才会得到一个const版本。与const指针和引用类似,可以将一个普通的iterator转换为对应的const_iterator,但反之不行。

以c开头的版本是C++新标准引入的,用以支持auto与begin和end函数结合使用。过去,没有其他选择,只能显式声明希望使用哪种类型的迭代器:

//显式指定类型
list<string>::iterator it5 = a.begin();
list<string>::const_iterator it6 = a.begin();

//是iterator还是const_iterator依赖于a的类型
auto it7 = a.begin(); //仅当a是const时,it7是const_iterator
auto it8 = a.cbegin();//it8是const_iterator

当auto与begin或end结合使用时,获得的迭代器类型依赖于容器类型,与我们想要如何使用迭代器毫不相干。但以c开头的版本还是可以获得const_iterator的,而不管容器的类型是什么。

Best Practices

当不需要写访问时,应使用cbegin和cend。

3. 容器操作可能使迭代器失效

向容器中添加元素和从容器中删除元素的操作可能会使指向容器元素的指针、引用或迭代器失效。一个失效的指针、引用或迭代器将不再表示任何元素。使用失效的指针、引用或迭代器是一种严重的程序设计错误,很可能引起与使用未初始化指针一样的问题。

在向容器添加元素后:

  • 如果容器是vector或string,且存储空间被重新分配,则指向容器的迭代器、指针和引用都会失效。如果存储空间未重新分配,指向插入位置之前的元素的迭代器、指针和引用仍有效,但指向插入位置之后元素的迭代器、指针和引用将会失效。
  • 对于deque,插入到除首尾位置之外的任何位置都会导致迭代器、指针和引用失效。如果在首尾位置添加元素,迭代器会失效,但指向存在的元素的引用和指针不会失效。
  • 对于list和forward_list,指向容器的迭代器(包括尾后迭代器和首前迭代器)、指针和引用仍有效。

当我们从一个容器中删除元素后,指向被删除元素的迭代器、指针和引用会失效,这应该不会令人惊讶。毕竟,这些元素都已经被销毁了。当我们删除一个元素后:

  • 对于list和forward_list,指向容器其他位置的迭代器(包括尾后迭代器和首前迭代器)、引用和指针仍有效。
  • 对于deque,如果在首尾之外的任何位置删除元素,那么指向被删除元素外其他元素的迭代器、引用或指针也会失效。如果是删除deque的尾元素,则尾后迭代器也会失效,但其他迭代器、引用和指针不受影响;如果是删除首元素,这些也不会受影响。
  • 对于vector和string,指向被删元素之前元素的迭代器、引用和指针仍有效。注意:当我们删除元素时,尾后迭代器总是会失效。

WARNING

使用失效的迭代器、指针或引用是严重的运行时错误。

建议:管理迭代器

当你使用迭代器(或指向容器元素的引用或指针)时,最小化要求迭代器必须保持有效的程序片段是一个好的方法。

由于向迭代器添加元素和从迭代器删除元素的代码可能会使迭代器失效,因此必须保证每次改变容器的操作之后都正确地重新定位迭代器。这个建议对vector、string和deque尤为重要。

3.1 编写改变容器的循环程序

添加/删除vector、string或deque元素的循环程序必须考虑迭代器、引用和指针可能失效的问题。程序必须保证每个循环步中都更新迭代器、引用或指针。如果循环中调用的是insert或erase,那么更新迭代器很容易。这些操作都返回迭代器,我们可以用来更新:

//傻瓜循环,删除偶数元素,复制每个奇数元素
vector<int> vi = { 0,1,2,3,4,5,6,7,8,9 };
auto iter = vi.begin();//调用begin而不是cbegin,因为我们要改变vi
while (iter != vi.end()) {
	if (*iter % 2) {
		iter = vi.insert(iter, *iter);//复制当前元素
		iter += 2;//向前移动迭代器,跳过当前元素以及插入到它之前的元素
	}else
		iter = vi.erase(iter);//删除偶数元素
		//不应向前移动迭代器,iter指向我们删除的元素之后的元素
}

此程序删除vector中的偶数值元素,并复制每个奇数值元素。我们在调用insert和erase后都更新迭代器,因为两者都会使迭代器失效。

在调用erase后,不必递增迭代器,因为erase返回的迭代器已经指向序列中下一个元素。调用insert后,需要递增迭代器两次。记住,insert在给定位置之前插入新元素,然后返回指向新插入元素的迭代器。因此,在调用insert后,iter指向新插入元素,位于我们正在处理的元素之前。我们将迭代器递增两次,恰好越过了新添加的元素和正在处理的元素,指向下一个未处理的元素。

3.2 不要保存end返回的迭代器

当我们添加/删除vector或string的元素后,或在deque中首元素之外任何位置添加/删除元素后,原来end返回的迭代器总是会失效。因此,添加或删除元素的循环程序必须反复调用end,而不能在循环之前保存end返回的迭代器,一直当作容器末尾使用。通常C++标准库的实现中end()操作都很快,部分就是因为这个原因。

例如,考虑这样一个循环,它处理容器中的每个元素,在其后添加一个新元素。我们希望循环能跳过新添加的元素,只处理原有元素。在每步循环之后,我们将定位迭代器,使其指向下一个原有元素。如果我们试图“优化”这个循环,在循环之前保存end()返回的迭代器,一直用作容器末尾,就会导致一场灾难:

//灾难:此循环的行为是未定义的
auto begin = v.begin(),
end = v.end();//保存尾迭代器的值是一个坏主意
while (begin != end) {
	//做一些处理
	//插入新值,对begin重新赋值,否则的话它就会失效
	++begin;//向前移动begin,因为我们想在此元素之后插入元素
	begin = v.insert(begin, 42);//插入新值
	++begin; // 向前移动begin跳过我们刚刚加入的元素
}

此代码的行为是未定义的。在很多标准库实现上,此代码会导致无限循环。问题在于我们将end操作返回的迭代器保存在一个名为end的局部变量中。在循环体中,我们向容器中添加了一个元素,这个操作使保存在end中的迭代器失效了。这个迭代器不再指向v中任何元素,或是v中尾元素之后的位置。

Tip

如果在一个循环中插入/删除deque、string或vector中的元素,不要缓存end返回的迭代器。

必须在每次插入操作后重新调用end(),而不能在循环开始前保存它返回的迭代器:

//更安全的方法:在每个循环步添加/删除元素后都重新计算end
while (begin != v.end() {
    //做一些处理
    ++begin;//向前移动begin,因为我们想在此元素之后插入元素
    begin = v.insert(begin, 42);//插入新值
    ++begin;//向前移动begin,跳过我们刚刚加入的元素
}

4. 反向迭代器

反向迭代器就是在容器中从尾元素向首元素反向移动的迭代器。对于反向迭代器,递增(以及递减)操作的含义会颠倒过来。递增一个反向迭代器(++it)会移动到前一个元素;递减一个迭代器(--it)会移动到下一个元素。

除了forward_list之外,其他容器都支持反向迭代器。我们可以通过调用rbegin、rend、crbegin和 crend成员函数来获得反向迭代器。这些成员函数返回指向容器尾元素和首元素之前一个位置的迭代器。与普通迭代器一样,反向迭代器也有const和非const版本。

下图显示了一个名为vec的假设的vector上的4种迭代器:

下面的循环是一个使用反向迭代器的例子,它按逆序打印vec中的元素:

vector<int> vec = { 0,1,2,3,4,5,6,7,8,9 };
//从尾元素到首元素的反向迭代器
for (auto r_iter = vec.crbegin();//将r_iter绑定到尾元素
		r_iter != vec.crend();   //crend指向首元素之前的位置
		++r_iter)                //实际是递减,移动到前一个元素
	cout << *r_iter << endl;     //打印9,8,7,...,0

虽然颠倒递增和递减运算符的含义可能看起来令人混淆,但这样做使我们可以用算法透明地向前或向后处理容器。例如,可以通过向sort传递一对反向迭代器来将vector整理为递减序:

sort(vec.begin(), vec.end());//按“正常序”排序vec
//按逆序排序:将最小元素放在vec的末尾
sort(vec.rbegin(), vec.rend());

4.1 反向迭代器需要递减运算符

不必惊讶,我们只能从既支持++也支持--的迭代器来定义反向迭代器。毕竟反向迭代器的目的是在序列中反向移动。除了forward_list之外,标准容器上的其他迭代器都既支持递增运算又支持递减运算。但是,流迭代器不支持递减运算,因为不可能在一个流中反向移动。因此,不可能从一个forward_list或一个流迭代器创建反向迭代器。

4.2 反向迭代器和其他迭代器间的关系

假定有一个名为line的string,保存着一个逗号分隔的单词列表,我们希望打印line中的第一个单词。使用find可以很容易地完成这一任务:

//在一个逗号分隔的列表中查找第一个元素
auto comma = find(line.cbegin(), line.cend(), ',');
cout << string(line.cbegin(), comma) << endl;

如果line中有逗号,那么comma将指向这个逗号;否则,它将等于line.cend()。当我们打印从line.cbegin()到comma之间的内容时,将打印到逗号为止的字符,或者打印整个string(如果其中不含逗号的话)。

如果希望打印最后一个单词,可以改用反向迭代器:

//在一个逗号分隔的列表中查找最后一个元素
auto rcomma = find(line.crbegin(), line.crend(), ',');

由于我们将crbegin()和crend()传递给find,find将从line的最后一个字符开始向前搜索。当find完成后,如果line中有逗号,则rcomma指向最后一个逗号——即,它指向反向搜索中找到的第一个逗号。如果line中没有逗号,则rcomma指向line.crend()。

当我们试图打印找到的单词时,最有意思的部分就来了。看起来下面的代码是显然的方法

//错误:将逆序输出单词的字符
cout << string(line.crbegin(), rcomma) << endl;

但它会生成错误的输出结果。例如,如果我们的输入是

FIRST,MIDDLE,LAST

则这条语句会打印TSAL!

下图说明了问题所在:我们使用的是反向迭代器,会反向处理string。因此,上述输出语句从 crbegin开始反向打印line中内容。而我们希望按正常顺序打印从rcomma开始到line末尾间的字符。但是,我们不能直接使用rcomma。因为它是一个反向迭代器,意味着它会反向朝着string的开始位置移动。需要做的是,将rcomma转换回一个普通迭代器,能在line中正向移动。我们通过调用reverse_iterator的base成员函数来完成这一转换,此成员函数会返回其对应的普通迭代器:

//正确:得到一个正向迭代器,从逗号开始读取字符直到line末尾
cout << string(rcomma.base(), line.cend()) << endl;

给定和之前一样的输入,这条语句会如我们的预期打印出LAST。

图中的对象显示了普通迭代器与反向迭代器之间的关系。例如,rcomma和rcomma.base()指向不同的元素,line.crbegin和line.cend()也是如此。这些不同保证了元素范围无论是正向处理还是反向处理都是相同的。

从技术上讲,普通迭代器与反向迭代器的关系反映了左闭合区间的特性。关键点在于[line.crbegin (), rcomma)和[rcomma.base(), line.cend())指向line中相同的元素范围。为了实现这一点,rcomma和rcomma.base()必须生成相邻位置而不是相同位置,crbegin()和cend()也是如此。

Note

反向迭代器的目的是表示元素范围,而这些范围是不对称的,这导致一个重要的结果:当我们从一个普通迭代器初始化一个反向迭代器,或是给一个反向迭代器赋值时,结果迭代器与原迭代器指向的并不是相同的元素。

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

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

相关文章

【SQL基础笔记】

本文标签: SQL语法 SQL分类 DDL DML DQL DCL 目录 一、SQL语法 二、SQL的分类 三、DDL 1.DDL-数据库操作 2.DDL-表操作 3.DDL-数据类型 4.DDL-表操作 四、DML 五、DQL 1.DQL-基本查询 2.DQL-条件查询: 3.DQL-聚合函数 4.DQL-分组查询 5.DQL-排序查询 6.DQL-分页查询 7.综合案…

让ChatGPT在中断回答的时候自动输入「请接上文继续」并发送

一、脚本内容 让ChatGPT在中断回答的时候自动输入「请接上文继续」并发送 // UserScript // name ChatGPT自动接上文继续 // namespace http://tampermonkey.net/ // version 1.3 // description 让ChatGPT在中断回答的时候自动输入「请接上文继续」并发送 /…

Elasticsearch:高级数据类型介绍

在我之前的文章 “Elasticsearch&#xff1a;一些有趣的数据类型”&#xff0c;我已经介绍了一下很有趣的数据类型。在今天的文章中&#xff0c;我再进一步介绍一下高级的数据类型&#xff0c;虽然这里的数据类型可能和之前的一些数据类型有所重复。即便如此&#xff0c;我希望…

MySQL数据同步ES的常用思路和方法

文章目录 1.同步双写2.异步双写3.定时任务4.数据订阅大家应该都在各种电商网站检索过商品,检索商品一般都是通过什么实现呢?搜索引擎Elasticsearch。 那么问题来了,商品上架,数据一般写入到MySQL的数据库中,那么用于检索的数据又是怎么同步到Elasticsearch的呢? 1.同步双…

认识Spring(下)

作者&#xff1a;~小明学编程 文章专栏&#xff1a;Spring框架 格言&#xff1a;热爱编程的&#xff0c;终将被编程所厚爱。 目录 Spring更加高效的读取和存储对象 存储bean对象 五大注解 关于五大类注解 对象的注入 属性注入 构造方法注入 Setter注入 三种注入方式的…

IPV6 资料收集

IPV6与IPV4区别 1、地址长度的区别&#xff1a;IPv4协议具有32位&#xff08;4字节&#xff09;地址长度&#xff1b;IPv6协议具有128位&#xff08;16字节&#xff09;地址长度。 2、地址的表示方法区别&#xff1a;IPv4地址是以小数表示的二进制数。 IPv6地址是以十六进制表…

4.1 读写不同数据源的数据

4.1 读写不同数据源的数据4.1.1 读写数据库数据1、数据库数据获取2、数据库数据存储4.1.2 读写文本文件1、文本文件读取2、文本文件存储4.1.3 读写Excel文件1、Excel文件读取2、Excel文件存储完整代码4.1.1 读写数据库数据 1、数据库数据获取 pandas提供了读取与存储关系型数…

为什么说网络安全行业是 IT 行业最后的红利?

一、为什么选择网络安全&#xff1f; 这几年随着我国《国家网络空间安全战略》《网络安全法》《网络安全等级保护 2.0》等一系列政策/法规/标准的持续落地&#xff0c;网络安全行业地位、薪资随之水涨船高。 未来 3-5 年&#xff0c;是安全行业的黄金发展期&#xff0c;提前踏…

Android OKHttp源码解析

Https是Http协议加上下一层的SSL/TSL协议组成的&#xff0c;TSL是SSL的后继版本&#xff0c;差别很小&#xff0c;可以理解为一个东西。进行Https连接时&#xff0c;会先进行TSL的握手&#xff0c;完成证书认证操作&#xff0c;产生对称加密的公钥、加密套件等参数。之后就可以…

jenkins打包发布前端项目

1.配置前端nodejs打包环境 1.1安装nodejs插件 1.2配置jenkins nodejs环境 2.下载git插件(使用此插件配置通过gitlab标签拉取项目) 3.创建一个自由风格的发布项目 4.配置项目构建流程 4.1添加钉钉告警 4.2配置参数化构建 4.3配置源码管理为git拉取项目 4.4配置构建环境 4.5配置…

Graphic Game(思维 + 模拟删点)

C-Graphic Game_2022年江西省大学生程序设计竞赛&#xff08;正式赛&#xff09; (nowcoder.com) Topic describes eightCirno被推荐了一个游戏&#xff0c;她决定今天和Daiyousei一起玩。最初&#xff0c;有一个具有2 n个顶点和m条边的图。在每一个转弯&#xff0c;Cirno和Da…

SpringBoot+Shiro框架整合实现前后端分离的权限管理基础Demo

记录一下使用SpringBoot集成Shiro框架实现前后端分离Web项目的过程&#xff0c;后端使用SpringBoot整合Shiro&#xff0c;前端使用vueelementUI&#xff0c;达到前后端使用token来进行交互的应用&#xff0c;这种方式通常叫做无状态&#xff0c;后端只需要使用Shiro框架根据前端…

【云原生进阶之容器】第五章容器运行时5.4--容器运行时之Firecracker

1 Firecracker诞生背景 近些年 AWS 非常推崇无服务器模式

用Cmake构建第一个C++项目

ps&#xff1a;由于工作需求&#xff0c;需要涉及到跨平台。 概念 Cmake是一个款平台的构建工具&#xff0c;可以自动生成各种不同平台和编译器的构建脚本&#xff0c;使得项目在不同平台和编译器下都能够正常构建和运行。 CMake有自己的一套语法&#xff0c;需要学习CMake的…

上海亚商投顾:两市成交创年内新高 人工智能再爆发

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪三大指数今日高开高走&#xff0c;沪指震荡反弹逼近3300点&#xff0c;创业板指午后涨超1.7%&#xff0c;科创50指数…

springboot 配置文件、多环境配置、运行优先级

前言 提问&#xff1a;springboot项目&#xff0c;开发环境、测试环境和生产环境配置文件如何分开表示&#xff1f; 答&#xff1a;多profile文件方式 1、多环境配置&#xff08;profile&#xff09; 1.1、properties文件配置 application.properties&#xff1a;主配置文…

基于html+css的between布局

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

【算法系列之动态规划IV】完全背包

完全背包 解题思路 01背包的核心思路&#xff0c;为了保证每个物品仅被添加一次&#xff0c;01背包内嵌的循环是从大到小遍历。 for(int i 0; i < weight.size(); i) { // 遍历物品for(int j bagWeight; j > weight[i]; j--) { // 遍历背包容量dp[j] max(dp[j], dp…

【云原生】k8s集群命令行工具kubectl之应用部署命令详解

kubectl应用部署命令详解一、准备工作1.1、Replication Controller1.2、Deployment1.3、DaemonSet1.4、查看创建的svc和pod1.5、kubectl 命令自动补全设置二、应用部署命令2.1、diff2.2、apply2.3、replace2.4、rollout2.4.1、history2.4.2、pause2.4.3、resume2.4.4、restart2…

Java 常量池分析

Java常量池 常量池&#xff1a;存放所有常量 常量池是Class文件中内容最为丰富的区域。常量池对于Class文件中的字段和方法解析也有着至关重要的作用。 随着Java虚拟机的不断发展&#xff0c;常量池的内容也日渐丰富。可以说&#xff0c;常量池是整个Class文件的基石。 在版…