【C++】STL---string

news2024/11/26 22:24:10

string类

  • 一、C语言中的字符串
  • 二、string类
  • 三、模拟实现 string 类
    • 0. string 类的声明
    • 1. 构造函数
    • 2. 析构函数
    • 3. 拷贝构造函数
    • 4. 赋值运算符重载
    • 5. 迭代器
    • 6. 元素访问:[] 重载
    • 7. 流插入与流提取重载
    • 8. 与容量相关的接口
      • (1)size
      • (2)capacity
      • (3)clear
      • (4)empty
      • (5)reserve
      • (6)resize
    • 9. 修改字符串的相关接口
      • (1)push_back
      • (2)append
      • (3)+= 运算符重载
      • (4)insert
      • (5)erase
    • 10. 操作字符串的接口
      • (1)c_str
      • (2)find
      • (3)substr
    • 11. 比较运算符重载

一、C语言中的字符串

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

二、string类

  1. string 是表示字符串的字符串类
  2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
  3. string 在底层实际是:basic_string 模板类的别名,typedef basic_string<char, char_traits, allocator> string;
  4. 不能操作多字节或者变长字符的序列。
  5. 在使用 string 类时,必须包含 #include 头文件以及 using namespace std;

其中,string 类的许多接口可以点击链接-> string 查看。

在这里需要介绍一下迭代器,在 string 类中,迭代器其实就是原生指针,迭代器的使用如下:

		#include <iostream>
		#include <string>
		using namespace std;
		
		int main()
		{
			string s1("hello,world");
		
			// 迭代器的使用,iterator 就是迭代器,它需要指定作用域
			string::iterator it = s1.begin();
			while (it != s1.end())
			{
				cout << *it << ' ';
				it++;
			}
			cout << endl;
		
			return 0;
		}

其中 s1.begin(); 其实就是指向字符串开始的指针,s1.end() 就是指向 ‘\0’ 的指针。

三、模拟实现 string 类

下面我们直接开始模拟实现 string 类的接口,在实现的过程中讲解用法,注意,我们只模拟比较常见和重要的接口。

我们先观察 string 类的声明部分,先预览一下我们需要实现哪些接口:

0. string 类的声明

		namespace Young
		{
			class String
			{
			public:
		
				// 迭代器
				typedef char* iterator;
				typedef const char* const_iterator;
				iterator begin();
				iterator end();
				const_iterator begin() const;
				const_iterator end() const;
		
		
				// 构造
				String(const char* str = "")
					:_str(new char [strlen(str) + 1])
					,_size(strlen(str))
					,_capacity(_size)
				{
					strcpy(_str, str);
				}
		
		
				// 析构
				~String()
				{
					delete[] _str;
					_str = nullptr;
					_size = _capacity = 0;
				}
		
				// 交换
				void swap(String& tmp)
				{
					::swap(_str, tmp._str);
					::swap(_size, tmp._size);
					::swap(_capacity, tmp._capacity);
				}
		
		
				// s2(s1)
				// 拷贝构造
				String(const String& str)
					:_str(nullptr)
					,_size(0)
					,_capacity(0)
				{
					String tmp(str._str);
					swap(tmp);
				}
		
		
				// s2 = s1
				// 赋值运算符重载
				String& operator=(const String& str)
				{
					if (this != &str)
					{
						String tmp(str._str);
						swap(tmp);
					}
		
					return *this;
				}
		
		
				// 申请空间 -- 不改变 _size
				void reserve(size_t n);
		
				// 将空间调整为 n -- 改变 _size
				void resize(size_t n, char c = '\0');
		
		
				// 尾插字符
				void push_back(char c);
				String& operator+=(char c);
		
		
				// 尾插字符串
				void append(const char* str);
				String& operator+=(const char* str);
		
		
				// 清空字符串
				void clear();
		
		
				// 获取字符串长度
				size_t size() const;
		
		
				// 获取容量
				size_t capacity() const;
		
		
				// [] 重载   s[1]
				const char& operator[](size_t index) const;
				char& operator[](size_t index);
		
		
				// 比较符号运算符重载
				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;
		
		
				// 返回它的字符串 -- 返回 char* 类型
				const char* c_str() const;
		
				// 判断是否为空字符串
				bool empty() const;
		
				// find -- 从pos位置开始查找字符/字符串
				size_t find(char ch, size_t pos = 0) const;
				size_t find(const char* str, size_t pos = 0) const;
		
		
				// 获得从 pos 位置开始到 len 的子字符串;如果 len 不给值,默认到结尾
				String substr(size_t pos, size_t len = npos) const;
		
				// 在 pos 位置插入插入字符 ch 或字符串 str
				String& insert(size_t pos, char ch);
				String& insert(size_t pos, const char* str);
		
				// 删除从 pos 位置开始 len 长度的字符串;如果 len 不给值就默认删到末尾 
				String& erase(size_t pos, size_t len = npos);
		
				// 打印数据
				void Print();
		
			private:
				char* _str;
				size_t _size;
				size_t _capacity;
		
			public:
				const static size_t npos = -1;
			};
		
			// 流插入、流提取      cout << s1;
			ostream& operator<<(ostream& out, const String& s);
			istream& operator>>(istream& in, String& s);
		}

1. 构造函数

构造函数往往是实现一个类首先需要考虑的,而 string 类的成员变量分别有 char* _str; size_t _size; size_t _capacity; ,虽然都是内置类型,但是 char* 类型需要我们手动申请空间,所以需要我们显式写构造函数:

			// 构造函数
			String(const char* str = "")
				:_str(new char [strlen(str) + 1])
				,_size(strlen(str))
				,_capacity(_size)
			{
				strcpy(_str, str);
			}

我们在构造函数中给了缺省值 "" 即空字符串;我们在申请空间的时候往往是要申请比 str 多一个空间,因为需要存放 '\0';最后我们使用 strcpy 函数将 str 拷贝到 _str 即可。

2. 析构函数

因为 string 类是我们手动申请空间的,所以要我们手动释放,析构函数如下:

			// 析构函数
			~String()
			{
				delete[] _str;
				_str = nullptr;
				_size = _capacity = 0;
			}

要注意使用 delete 需要匹配使用。

3. 拷贝构造函数

在这里的拷贝构造函数中,我们就需要回顾一下浅拷贝深拷贝了,我们此前也在 类和对象(中篇) 了解过,现在来回顾一下。

  1. 浅拷贝: 也称值拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。

我们可以采用深拷贝解决浅拷贝问题,即:每个对象都有一份独立的资源,不要和其他对象共享。

  1. 深拷贝: 如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。

下面我们自己显式写一个 string 类的拷贝构造函数:

			// String s2(s1);
			// 拷贝构造
			String(const String& str)
				:_str(nullptr)
				,_size(0)
				,_capacity(0)
			{
				String tmp(str._str);
				swap(tmp);
			}

注意,上面的拷贝构造中,假设是这样: String s2(s1);_str 就是 s2 对象的,strs1 对象的,我们的思路是首先将 _str 走初始化列表置空,_size_capacity 置零,然后利用构造函数 String tmp(str._str); 实例化一个 tmp 对象,此时 tmp 相当于是 s1 ,最后将 s2tmp 对象中的资源交换,即完成了 s1 拷贝给 s2;而且出了作用域 tmp 还会自动调用析构函数析构。

注意以上的 swap 函数也是 string 类中的,所以也需要我们自己实现,实现如下:

			// 交换
			void swap(String& tmp)
			{
				std::swap(_str, tmp._str);
				std::swap(_size, tmp._size);
				std::swap(_capacity, tmp._capacity);
			}

在实现中,我们再利用标准库中的 swap 函数帮助我们完成 string 类的swap 函数。

使用和结果如下图:

在这里插入图片描述

4. 赋值运算符重载

赋值运算符重载也和拷贝构造差不多,实现如下:

			// s2 = s1
			// 赋值运算符重载
			String& operator=(const String& str)
			{
				if (this != &str)
				{
					String tmp(str._str);
					swap(tmp);
				}
	
				return *this;
			}

使用和结果如下:

在这里插入图片描述

5. 迭代器

string 类的迭代器其实就是原生指针,声明在上面的 string 类声明中,下面我们直接实现:

		// 迭代器
		Young::String::iterator Young::String::begin()
		{
			return _str;
		}
		
		Young::String::iterator Young::String::end()
		{
			return _str + _size;
		}
		
		Young::String::const_iterator Young::String::begin() const
		{
			return _str;
		}
		
		Young::String::const_iterator Young::String::end() const
		{
			return _str + _size;
		}

由于我们是声明和定义分离写,所以在 iterator/const_iteratorbegin()/end() 前都要指定我们的作用域;其中 iterator/const_iterator 分别是普通对象调用的迭代器和 const 对象调用的迭代器;begin()/end() 分别是指向字符串的头和尾的指针。

6. 元素访问:[] 重载

为了方便访问 string,我们可以重载 [] 可以直接访问下标,实现如下:

const对象:

		const char& Young::String::operator[](size_t index) const
		{
			assert(index < _size);
		
			return _str[index];
		}

普通对象:

		char& Young::String::operator[](size_t index)
		{
			assert(index < _size);
		
			return _str[index];
		}

7. 流插入与流提取重载

在使用 string 的时候,为了方便查看字符串,我们可以重载流插入和流提取,方便打印查看字符串;在以前讲过,我们为了方便我们的使用以及体现流插入和提取的使用价值,我们要在类外面实现,防止 this 指针抢占第一个参数位置,实现如下:

		// 流插入    cout << s1;
		ostream& Young::operator<<(ostream& out, const String& s)
		{
			for (size_t i = 0; i < s.size(); i++)
			{
				out << s[i];
			}
			return out;
		}

流插入中我们只需要将每一个字符打印出来即可;

		// 流提取    cin >> s
		istream& Young::operator>>(istream& in, String& s)
		{
			s.clear();
		
			char buff[129];
			size_t i = 0;
		
			char ch = in.get();
		
			while (ch != ' ' && ch != '\n')
			{
				buff[i++] = ch;
				if (i == 128)
				{
					buff[i] = '\0';
					s += buff;
					i = 0;
				}
				ch = in.get();
			}
		
			if (i != 0)
			{
				buff[i] = '\0';
				s += buff;
			}
		
			return in;
		}

我们创建一个 buff 数组,存放输入的字符,当 buff 数组满了就一把插入到对象中,避免频繁开辟空间;因为流提取默认遇到 ' ''\0' 就结束,所以我们需要用 cin 的成员函数 get() 提取到 ' ''\0' ,方便我们判断结束条件。

8. 与容量相关的接口

(1)size

获取字符串的有效长度,实现:

		size_t Young::String::size() const
		{
			return _size;
		}

(2)capacity

获取字符串的容量,实现:

		size_t Young::String::capacity() const
		{
			return _capacity;
		}

(3)clear

清空字符串的内容,实现:

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

清空字符串的内容并不是销毁空间,所以只需要在下标为 0 位置加上 '\0' 即可,并将长度置 0.

(4)empty

判断字符串是否为空字符串,实现:

		bool Young::String::empty() const
		{
			return _size == 0;
		}

只需要判断 _size 是否为 0.

上面四个接口的使用如下:

在这里插入图片描述

(5)reserve

我们可以查看 reserve 接口的相关文档:

在这里插入图片描述

其实就是申请 n 个空间,reserve 有保留的意思,就是有保留 n 个空间的意思,n 大于 _capacity 就改变空间,小于则不用改变;注意 reserve 不改变 _size 的值;其实现如下:

		// 申请空间
		void Young::String::reserve(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
		
				delete[] _str;
				_str = tmp;
		
				_capacity = n;
			}
		}

假设需要申请 n 个空间,就需要申请 n+1 空间,给 '\0' 预留一个空间;然后将原来字符串中的内容拷贝到新开辟的空间中,然后销毁原来的空间 _str,让原来的空间 _str 指向新的空间 tmp

(6)resize

reserveresize 的区别就是 resize 是调整空间的大小,并可以初始化空间,resize 是可以改变 _size 的值的。

		// 调整空间+初始化
		void Young::String::resize(size_t n, char c)
		{
			// 如果 n 大于 _size,直接申请 n 个空间,然后从原来的尾部开始初始化 
			if (n > _size)
			{
				reserve(n);
		
				for (size_t i = _size; i < n; i++)
				{
					_str[i] = c;
				}
		
				_str[n] = '\0';
				_size = n;
			}
		
			// 否则,删数据
			else
			{
				_str[n] = '\0';
				_size = n;
			}
		}

初始化的字符如果没有显式传,会使用我们在声明处给的缺省值 '\0

9. 修改字符串的相关接口

(1)push_back

尾插,在字符串尾部插入一个字符,我们先看原文档:

在这里插入图片描述
实现如下:

		// 尾插字符
		void Young::String::push_back(char c)
		{
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}
		
			_str[_size++] = c;
			_str[_size] = '\0';
		}

尾插之前需要判断容量是否已经满了,满了就要扩容;或者容量是 0,我们就默认开 4 个容量。

(2)append

追加字符串,我们先看文档:

在这里插入图片描述

文档中重载了许多接口,我们在这里只实现一个接口,就是尾插字符串,也就是上图中的第三个接口,实现如下:

		// 尾插字符串
		void Young::String::append(const char* str)
		{
			int len = strlen(str);
		
			// 空间不够扩容
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
		
			strcpy(_str + _size, str);
			_size += len;
		}

(3)+= 运算符重载

在这里插入图片描述

+= 运算符也是追加字符、字符串、string 对象,我们在这里实现追加字符和字符串,也就是尾插,其实现如下:

		//尾插字符
		Young::String& Young::String::operator+=(char c)
		{
			push_back(c);
		
			return *this;
		} 

有了之前实现的 push_backappend ,我们只需要复用它们就可以实现了;

		// 尾插字符串
		Young::String& Young::String::operator+=(const char* str)
		{
			append(str);
		
			return *this;
		}

以上四个接口的使用与流插入流提取的使用如下:

在这里插入图片描述

(4)insert

insert 是在 pos 位置插入字符 ch 或字符串 str,我们就实现插入字符或字符串的接口,实现如下:

		// 插入字符
		Young::String& Young::String::insert(size_t pos, char ch)
		{
			assert(pos < _size);
		
			// 满了就扩容
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}
		
			// 挪动数据
			size_t end = _size + 1;
			while (end > pos)
			{
				_str[end] = _str[end - 1];
				end--;
			}
		
			// 插入字符
			_str[pos] = ch;
			_size++;
		
			return *this;
		}

插入字符串:

		Young::String& Young::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)
			{
				_str[end] = _str[end - len];
				end--;
			}
		
			// 拷贝数据1.
			/*for (size_t i = pos; i < len; i++)
			{
				_str[i] = str[i];
			}*/
		
			// 拷贝数据2.
			strncpy(_str + pos, str, len);
			_size += len;
		
			return *this;
		}

(5)erase

erase 是删除从 pos 位置开始 len 长度的字符串;如果 len 不给值就默认删到末尾;

到末尾我们需要在声明处定义一个 npos 的静态无符号变量,将它定义为 -1 ,因为是无符号,所以它是整型的最大值,我们在缺省值处给 npos ,即可取到末尾。注意,如果声明和定义分离写,缺省值只能给在声明处。

实现如下:

		Young::String& Young::String::erase(size_t pos, size_t len)
		{
			assert(pos < _size);
			
			// 删到末尾
			if (len == npos || pos + len > _size)
			{
				_str[pos] = '\0';
				_size = pos;
			}
		
			// 删 len 长度
			else
			{
				strcpy(_str + pos, _str + pos + len);
				_size -= len;
			}
		
			return *this;
		}

insert 和 erase 的使用如下图:

在这里插入图片描述

10. 操作字符串的接口

(1)c_str

返回它的字符串 - 返回 char* 类型,实现:

		const char* Young::String::c_str() const
		{
			return _str;
		}

(2)find

find 是查找函数的接口,从 pos 位置开始查找字符/字符串,pos 不给值默认下标从 0 开始找,实现如下:

查找字符:

		size_t Young::String::find(char ch, size_t pos) const
		{
			assert(pos < _size);
		
			for (size_t i = pos; i < _size; i++)
			{
				if (_str[i] == ch)
				{
					// 返回下标
					return i;
				}
			}
		
			return npos;
		}

查找字符串:

		size_t Young::String::find(const char* str, size_t pos) const
		{
			assert(pos < _size);
			assert(str);
		
			const char* ret = strstr(_str + pos, str);
			if (ret == nullptr)
				return npos;
		
			// 下标相减,返回下标
			return ret - _str;
		}

strstr 是查找匹配字串的库函数,它的返回值是如果找到就返回匹配字串的开头,否则返回空。

(3)substr

substr 是获得从 pos 位置开始到 len 的子字符串;如果 len 不给值,默认到结尾,即 npos,实现如下:

		Young::String Young::String::substr(size_t pos, size_t len) const
		{
			assert(pos < _size);
		
			// 创建一个临时对象 tmp
			String tmp;
		
			// end 为取到的子串的结尾的下标
			size_t end = pos + len;
		
			// 取到末尾
			if (len == npos || end > _size)
			{
				len = _size - pos;
				end = _size;
			}
		
			// 申请 len 的空间
			tmp.reserve(len);
		
			// 开始取子串
			for (size_t i = pos; i < end; i++)
			{
				tmp += _str[i];
			}
		
			return tmp;
		}

一般 findsubstr 一起使用,它们的使用场景可以将一个网址分割成协议、域名、资源名,使用如下:

在这里插入图片描述

11. 比较运算符重载

我们也像以前一样,只需要实现 >== 运算符,其它的都复用这两个就可以了,实现如下:

		bool Young::String::operator>(const String& s) const
		{
			return strcmp(_str, s._str) > 0;
		}
		
		bool Young::String::operator==(const String& s) const
		{
			return strcmp(_str, s._str) == 0;
		}
		
		bool Young::String::operator>=(const String& s) const
		{
			return *this > s || *this == s;
		}
		
		bool Young::String::operator<(const String& s) const
		{
			return !(*this >= s);
		}
		
		bool Young::String::operator<=(const String& s) const
		{
			return !(*this > s);
		}
		
		bool Young::String::operator!=(const String& s) const
		{
			return !(*this == s);
		}

使用和结果如下:

在这里插入图片描述

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

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

相关文章

使用CST仿真软件完成单站雷达目标RCS仿真

第一步&#xff1a;新建模版 第二步&#xff1a;选择微波与射频/光学应用 第三步&#xff1a;选择雷达应用 第四步&#xff1a;选择单站雷达静态RCS 第五步&#xff1a;选择小目标工作流。&#xff08;这里的小目标要求小于10倍波长&#xff0c;否则需要选大目标工作流&#x…

nuxt3 简易教程

代码仓库 https://github.com/malred/nuxt_tutorial https://gitee.com/malguy/nuxt_tutorial 什么是 Nuxt 根据 Vue 官网的说法 而 Nuxt 是由 Vue 官方团队开发的 SSR 框架 创建项目 npx nuxi init todo 项目结构 创建完需要手动安装依赖 cd todo npm i # 启动 npm run dev…

大语言模型之二 GPT发展史简介

得益于数据、模型结构以及并行算力的发展&#xff0c;大语言模型应用现今呈井喷式发展态势&#xff0c;大语言神经网络模型成为了不可忽视的一项技术。 GPT在自然语言处理NLP任务上取得了突破性的进展&#xff0c;扩散模型已经拥有了成为下一代图像生成模型的代表的潜力&#x…

@capacitor/filesystem更改downloadfile支持本地文件下载

ionic监听外部程序&#xff1a; android下需要在AndroidManifest.xml添加内容&#xff08;具体参考ionic native的APP插件&#xff09;&#xff0c;配置例如&#xff1a; <intent-filter tools:ignore"AppLinkUrlError"><action android:name"android.…

【Matlab智能算法】PSO优化(单隐层)BP神经网络算法

上一篇博客介绍了BP-GA&#xff1a;BP神经网络遗传算法(BP-GA)函数极值寻优——非线性函数求极值&#xff0c;本篇博客将介绍用PSO&#xff08;粒子群优化算法&#xff09;优化BP神经网络。 1.优化思路 BP神经网络的隐藏节点通常由重复的前向传递和反向传播的方式来决定&#…

(统计学习方法|李航)第四章 朴素贝叶斯算法——贝叶斯估计

贝叶斯估计方法&#xff1a; 计算男女时只有两个值&#xff0c;所以K2 贝叶斯估计就是拉普拉斯平滑 估计方法&#xff1a;为什么叫做贝叶斯估计呢&#xff1f; 例题&#xff1a; 重新回顾以下朴素贝叶斯&#xff1a; 对他求导&#xff0c;求出最大值 得到了色i他的估计值&…

第三章:前端UI框架介绍

文章目录 一、Bootstrap1.1 Bootstrap简介及版本1.2 Bootstrap使用 二、AntDesign2.1 简介2.2 基本使用2.3 antd pro 三、ElementUI3.1 简介3.2 基本使用 四、Vant4.1 简介4.2 基本使用 一、Bootstrap 1.1 Bootstrap简介及版本 1、 简介 Bootstrap&#xff0c;来白 Twitter&a…

服务管理和计划任务

文章目录 服务管理计划任务 服务管理 systemctl 命令字 服务名 //配置服务与systemctl有关的命令字&#xff1a; 计划任务 一次性计划 at 时间 at now 5 min //当前时间五分钟后执行 at -l //列出计划任务 atrm 任务号 //删除计划任务执行完命令后Ctrld生效 周期性计…

LiveNVR监控流媒体Onvif/RTSP功能-视频流水印如何叠加视频水印叠加动态图片叠加视频流时间示例

LiveNVR视频流水印如何叠加视频水印叠加动态图片叠加视频流时间示例 1、介绍2、摄像头OSD设置水印3、前端页面叠加4、视频流水印4.1、图片水印示例4.2、时间戳水印示例 5、RTSP/HLS/FLV/RTMP拉流Onvif流媒体服务 1、介绍 监控视频平台播放视频监控的时候&#xff0c;除了满足正…

提升效率!云原生生态从业人员不可或缺的工具集合!

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

shell脚本安装nginx

文章目录 shell脚本原理变量脚本安装nginx shell脚本原理 以删除桌面文件的脚本为例&#xff0c;执行脚本后&#xff0c;shell脚本将代码给内核&#xff0c;内核读取后执行命令&#xff0c;如果shell脚本也在桌面上&#xff0c;执行后这个脚本文件也会被删除。 变量 echo $SH…

Java程序控制结构,一文带你彻底拿下~

—— 程序的运行流程控制会解决程序是如何执行的 三大程序流程控制结构 1&#xff09;顺序结构&#xff1a;程序从上到下逐行逐行的执行&#xff0c;中间没有任何的判断和跳转 2&#xff09;分支结构&#xff1a;程序具有选择性的进入某一段代码 3&#xff09;循环结构&#xf…

SQL Developer中的Data Redaction

SQL Developer中的Data Redaction用起来比命令行方便多了。可以选定表或视图&#xff0c;右键点击“遮盖保护”菜单。 但赋权方面有需要注意的地方。 假设Redact Admin是SYS&#xff0c;Redact User是HR。虽然SYS具备所有权限&#xff0c;但还是报以下错误。其实这个错误是针…

jvm——垃圾回收机制(GC)详解

开始之前有几个GC的基本问题 什么是GC&#xff1f; GC 是 garbage collection 的缩写&#xff0c;意思是垃圾回收——把内存&#xff08;特别是堆内存&#xff09;中不再使用的空间释放掉&#xff1b;清理不再使用的对象。 为什么要GC&#xff1f; 堆内存是各个线程共享的空间…

spring常用注解标签总结

1&#xff1a;Component等 名称Component/Controller/Service/Repository类型类注解位置类定义上方作用设置该类为spring管理的bean属性value&#xff08;默认&#xff09;&#xff1a;定义bean的id 说明: Component注解如果不起名称&#xff0c;会有一个默认值就是当前类名首…

IDEA提示:StringBuffer xxx‘ may be declared as ‘StringBuilde

如图所示&#xff0c;编写代码时遇见了如下IDEA警告&#xff1a; 原因&#xff1a;StringBuilder是线程不安全的&#xff0c;但是其效率高&#xff0c;而StringBuffer则相反&#xff0c;虽然其线程安全&#xff0c;但是效率低下。 由于 StringBuilder 相较于 StringBuffer 有速…

Java+Excel+POI+testNG基于数据驱动做一个简单的接口测试【杭州多测师_王sir】

一、创建一个apicases.xlsx放入到eclipse的resource里面&#xff0c;然后refresh刷新一下 二、在pom.xml文件中加入poi和testng的mvn repository、然后在eclipse的对应目录下放入features和plugins&#xff0c;重启eclipse就可以看到testNG了 <!--poi excel解析 --><d…

音视频研发分享:关键帧截图+wasm快照--我又做了一件有益于社会的事情

音视频研发分享&#xff1a;关键帧截图wasm快照--我又做了一件有益于社会的事情 简单的一个视频设备快照功能到底有多费事多费电&#xff1f;新的方法有方法&#xff01; 省了多少电&#xff1f; 简单的一个视频设备快照功能到底有多费事多费电&#xff1f; 以前&#xff0c;我…

【C# 基础精讲】构造函数和析构函数

构造函数&#xff08;Constructor&#xff09;和析构函数&#xff08;Destructor&#xff09;是面向对象编程中的两个重要概念&#xff0c;它们分别用于在对象创建和销毁的时候执行特定的操作。这两个函数在C#以及其他面向对象编程语言中都具有重要的作用&#xff0c;用于初始化…

机器学习笔记:李宏毅chatgpt 大模型 大资料

1 大模型 1.1 大模型的顿悟时刻 Emergent Abilities of Large Language Models&#xff0c;Transactions on Machine Learning Research 2022 模型的效果不是随着模型参数量变多而慢慢变好&#xff0c;而是在某一个瞬间&#xff0c;模型“顿悟”了 这边举的一个例子是&#…