秒懂C++之string类(下)

fe594ea5bf754ddbb223a54d8fb1e7bc.gif

目录

一.接口说明

1.1 erase

1.2 replace(最好别用)

1.3 find

1.4 substr

1.5 rfind

1.6 find_first_of

1.7 find_last_of

二.string类的模拟实现

2.1 构造

2.2 无参构造

2.3 析构

2.4.【】运算符

2.5 迭代器

2.6 打印

2.7 reserve扩容

2.8 push_back尾插

2.9 append追加

2.10 insert插入

2.11 erase删除

2.12 swap交换

2.13 find寻找

2.14 运算符+=

2.15 substr

2.16 流插入<<

2.17 流提取>>

三.现代写法

拷贝构造

赋值拷贝

四.小拓展

五.全部代码


一.接口说明

1.1 erase

#include <iostream>
#include <string>
using namespace std;int main()
{string s1("hello world");s1.erase(0, 4);cout << s1 << endl;//o world 从下标为0开始,删除4个字符s1.erase();cout << s1 << endl;//return 0;}

1.2 replace(最好别用)

int main()
{string s1("hello world");string s2;s1.replace(0, 1, "aaaa");cout << s1 << endl;//aaaaello worldreturn 0;
}

替换指定位置内容,并挪动后面数据。

1.3 find

int main()
{string s1("hello world a b");// 所有的空格替换为100%size_t pos = s1.find(' ', 0);//从下标为0位置开始找while (pos != string::npos){s1.replace(pos, 1, "100%");// 效率很低,能不用就不要用了pos = s1.find(' ', pos + 4);}cout << s1 << endl;//hello100%world100%a100%breturn 0;
}

作用就是从头开始找到该字符并返回其下标位置。

之所以不用replace是因为有更好的替代~ 


int main()
{string s1("hello world a b");string s2;for (auto ch : s1){if (ch == ' '){s2 += "100%";}else{s2 += ch;}}s1.swap(s2);cout << s1 << endl;//hello100%world100%a100%breturn 0;
}

注意:

swap(s1,s2)与s1.swap(s2)可不一样,前者是通过有个中间变量进行交换,而后者是让双方指针进行交换,后者更为高效~

1.4 substr

int main()
{string s1("hello");string s2;s2 = s1.substr(1, 2);cout << s2 << endl;//elcout << s1.substr(1) << endl;//elloreturn 0;
}
str 中从 pos 位置开始,截取 n 个字符,然后将其返回

1.5 rfind

从末尾开始找字符并返回下标

int main()
{//获取后缀名string s1("Test.cpp");string s2("Test.tar.zar");size_t pos1 = s1.find('.');size_t pos2 = s2.rfind('.');if(pos1 != string::npos){string s3 = s1.substr(pos1);cout << s3 << endl;//.cppstring s4 = s2.substr(pos2);cout << s4 << endl;//.zar}return 0;
}

1.6 find_first_of

int main()
{string s1("hello world");size_t pos1 = s1.find_first_of("abcde");cout << pos1 << endl;//1pos1 = s1.find_first_of("ow");cout << pos1 << endl;//4return 0;
}

返回在选定字符串中任意一个字符第一次出现的下标。(从头开始遍历)

1.7 find_last_of

int main()
{string s1("hello world");size_t pos1 = s1.find_last_of("abcde");cout << pos1 << endl;//10pos1 = s1.find_last_of("h");cout << pos1 << endl;//0return 0;
}

返回在选定字符串中任意一个字符第一次出现的下标。(从尾开始遍历)

注意:find_first_not_of与find_last_not_of,就是返回指选定字符串之外的字符下标

int main()
{string s1("hello world");size_t pos1 = s1.find_first_not_of("abcde");cout << pos1 << endl;//0pos1 = s1.find_last_not_of("h");cout << pos1 << endl;//10return 0;
}

二.string类的模拟实现

2.1 构造

首先实现构造函数的时候在初始化列表不能直接这么写,涉及到了权限放大~

也不能在私有成员那写:const char* _str,这样_str以后只能指向一处,无法修改指向,也意味着无法增删改。

namespace lj
{class string{public://构造string(const char* str){_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];//加1是因为在_capacity那被认为‘\0’是有效字符strcpy(_str, str);}private:size_t _size;size_t _capacity;char* _str;};void test_string1(){string s1("aabbcc");//构造成功}
}

建议直接放弃在列表初始化,还得考虑声明顺序啥的挺麻烦~

2.2 无参构造

//无参构造string(){_str = nullptr;_size = 0;_capacity = 0;}//返回c格式字符串const char* c_str(){return _str;}

可惜这种无参写法不行,因为c_str是以指针的形式返回的(字符串形式),而cout接触到指针会认为是要打印字符串,直接解引用指针,一个空指针被解引用是错误的。

开辟个1字节的空间,里面放个字符(但不是有效字符)

不过与其写无参不如直接写缺省参数

//为什么字符串就能匹配上啊?,因为这样指针就能指向它,本身是地址。

2.3 析构

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

2.4.【】运算符

		char& operator[](size_t pos){return _str[pos];}

//为什么里面还能有【】,因为这个是给内置类型使用的,自定义类型要自己自定义

2.5 迭代器

typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}

其实迭代器实现也挺简单的~

for+auto的遍历底层逻辑其实还是迭代器。

2.6 打印

首先调用size()函数的时候出现了权限放大的问题,调用运算符【】也是如此所以在这里我们就要引入const成员函数进行修改~对需要改变自身的额外再写一个针对const权限函数,对不需要改变自身的加入const。

void print_str(const string& s){for (size_t i = 0; i < s.size(); i++){//s[i]++;cout << s[i] << endl;}string::const_iterator it = s.begin();while (it != s.end()){// *it = 'x';cout << *it << " ";++it;}cout << endl;}

2.7 reserve扩容

		void reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];//还有一个开给\0strcpy(tmp, _str);//拷贝所指向的内容delete[] _str;//销毁旧空间_str = tmp;//指向新空间_capacity = n;}}

2.8 push_back尾插

void push_back(char ch){if (_size == _capacity){size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newcapacity);}_str[_size] = ch;_size++;_str[_size] = '\0';}

由于\0不算有效字符,所以最后计算完后_size都会与其下标相等,而这时候可以刚好插入字符。最后需要注意人工补上\0。

2.9 append追加

		void append(const char* str){size_t len = strlen(str);//计算所追加的长度if (_size + len > _capacity){reserve(_size + len);}strcpy(_str+_size, str);_size += len;}

//strcpy(_str+_size, str);为什么不是_size就行了呢?因为_size是一个数据不是一个指针,而_str是指针+数可以达到偏移的效果

2.10 insert插入

		void 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;while (pos < end){_str[end] = _str[end - 1];end--;}_str[pos] = ch;_size++;_str[_size] = '\0';}

需要注意的细节有点多:如果是这种写法

while (end >= (int)pos){_str[end + 1] = _str[end];--end;}

最后end会减为负数,而其类型又是无符号整型,会一直陷入死循环。就算把end改为整型,在循环条件里又会和pos触发类型提升(小的向大的转,有符号向无符号转),最后还得强制转化pos类型才可以解决问题。所以直接换个写法一劳永逸~

		void 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;while (pos < end){_str[end+len-1] = _str[end - 1];end--;}strncpy(_str + pos, str,len);_size+=len;_str[_size] = '\0';}

 

2.11 erase删除

void erase(size_t pos, size_t len = npos){assert(pos <= _size);if (len == npos || pos + len > _size){_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);//很精妙_size -= len;}}

2.12 swap交换

void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}

如果没有中间的swap(string),那么swap(s1,s2)就会走与swap(a,b)一样的结果,产生中间变量。如果有中间的swap(string),那当我们swap(s1,s2)时进入其中就会让我们去调用string类里面的swap,只需要交换指针即可,不产生中间变量。

2.13 find寻找

size_t find(char ch, size_t pos = 0){for (size_t i = pos; i <= _size; i++){if (_str[i] == ch){return i;}}return npos;}

 

		size_t find(const char*str, size_t pos = 0){const char* ptr = strstr(_str + pos, str);if (ptr == nullptr){return npos;}else{return ptr - _str;//利用指针-指针}}

2.14 运算符+=

        string& operator+=(char ch){push_back(ch);return *this;}string& operator+=(const char* str){append(str);return *this;}

简单复用即可

2.15 substr
 

		string substr(size_t pos = 0, size_t len = npos){assert(pos < _size);size_t end = pos+len;if (len == npos || pos + len >= _size){end = _size;}string sub1;sub1.reserve(end - pos);//重新创个空间for (size_t i = pos; i < end; i++)//拷贝内容{sub1 += _str[i];}return sub1;}

最终会报错~

问题一:因为是临时对象,这意味着出作用会就会调用析构函数(清理资源),而临时对象又指向临时资源,被清理后那就变成野指针了。

解决方法:写出拷贝构造(深拷贝)

string(const string& s){//深拷贝_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}

问题二:在赋值拷贝中(s2=s1)会出现以下情况,要么s2的空间过大,与s1大小差距过大造成资源浪费。要么s2的空间太小,不足够容纳s1,只有二者刚刚好才合适。

// s2 = s1
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;}

既然这样就重新构造一个与s1相仿的空间,再拷贝原内容进去,删掉s2所指的原来空间,令s2指向新空间,再浅拷贝,使得赋值拷贝合理化。

成功实现效果~ 

2.16 流插入<<

	ostream& operator<<(ostream& out, const string& s){for (auto ch : s){out << ch;}return out;}

2.17 流提取>>

	void clear(){_size = 0;_str[0] = '\0';}istream& operator>>(istream& in,  string& s){s.clear();char ch = in.get();while (ch != ' ' && ch != '\n'){s += ch;ch = in.get();}return in;}

细节一:clear函数

如果没有_str[0] = '\0';由于cout<<s1是以_size为准的,在遍历的时候就停止流插入了。而cout<<s1.c_str()中由于其返回的是整段的字符串不看_size,是直接解引用的。那么在没有'\0'的情况下还是会输出,没有达成清理的效果。

另外如果没有clear函数清理原内容,那么cin最后做到的只是拼接。

细节二.get函数

如果ch以这样的方式提取那么最终会无法识别到‘ ’与‘\n’而死循环。因为in拿不到‘ ’与‘\n’,他们通常是作为分割符合使用的,所以会无视。只有get函数才能够识别并提取它们。

三.现代写法

备注:功能和传统写法一组,只是让代码行数更少

拷贝构造

		//传统写法			string s2(s1) string(const string& s){//深拷贝_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}//现代写法			string s2(s1) string(const string& s){string tmp(s._str);//调用构造,构造出与s1一样的空间与内容swap(tmp);//s2与tmp交换指针}

细节:s2必须得指向空(全缺省),如果指向其他地方那么tmp可能会出现随机值,报错。

赋值拷贝

        //传统写法  s1 = s3string& 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;}//现代写法  s1 = s3string& operator=(string s){swap(s);return *this;}

四.小拓展

to_string可以识别各种类型然后转化为string。

stoi可以识别string类型然后转化为需要的类型。

五.全部代码

//string.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "string.h"namespace lj
{//构造string::string(const char* str)//不能给'\0'类型不匹配,而字符串会默认带\0{_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];//加1是因为在_capacity那被认为‘\0’是有效字符strcpy(_str, str);}//现代写法			string s2(s1) string::string(const string& s){string tmp(s._str);//调用构造swap(tmp);}//现代写法  s1 = s3string& string::operator=(string s){swap(s);return *this;}string::~string(){delete[] _str;_str = nullptr;_size = 0;_capacity = 0;}char& string::operator[](size_t pos){return _str[pos];}const char& string:: operator[](size_t pos)const{return _str[pos];}void string::reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 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;_size++;_str[_size] = '\0';}void string::append(const char* str){size_t len = strlen(str);//计算所追加的长度if (_size + len > _capacity){reserve(_size + len);}strcpy(_str + _size, str);_size += len;}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;while (pos < end){_str[end] = _str[end - 1];end--;}_str[pos] = ch;_size++;_str[_size] = '\0';}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;while (pos < end){_str[end + len - 1] = _str[end - 1];end--;}strncpy(_str + pos, str, len);_size += len;_str[_size] = '\0';}void string::erase(size_t pos, size_t len){assert(pos <= _size);if (len == npos || pos + len > _size){_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);//很精妙_size -= len;}}void string::swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}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){const char* ptr = strstr(_str + pos, str);if (ptr == nullptr){return npos;}else{return ptr - _str;//利用指针-指针}}string& string::operator+=(char ch){push_back(ch);return *this;}string& string::operator+=(const char* str){append(str);return *this;}string string::substr(size_t pos, size_t len){assert(pos < _size);size_t end = pos + len;if (len == npos || pos + len >= _size){end = _size;}string sub1;sub1.reserve(end - pos);//重新创个空间for (size_t i = pos; i < end; i++)//拷贝内容{sub1 += _str[i];}return sub1;}void string::clear(){_size = 0;_str[0] = '\0';}ostream& operator<<(ostream& out, const string& s){for (auto ch : s){out << ch;}return out;}istream& operator>>(istream& in, string& s){s.clear();char ch = in.get();while (ch != ' ' && ch != '\n'){s += ch;ch = in.get();}return in;}};

//string.h
#pragma once
#include <iostream>
#include <assert.h>
using namespace std;
namespace lj
{class string{public://无参构造/*	string():_str(new char[1]){_str[0] = '\0';_size = 0;_capacity = 0;}*///返回c格式字符串const char* c_str()const{return _str;}//构造string(const char* str = "");//不能给'\0'类型不匹配,而字符串会默认带\0//现代写法			string s2(s1) string(const string& s);//现代写法  s1 = s3string& operator=(string s);~string();size_t size()const{return _size;}typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}const_iterator begin()const{return _str;}iterator end(){return _str + _size;}const_iterator end()const{return _str + _size;}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);void insert(size_t pos, char ch);void insert(size_t pos, const char* str);void erase(size_t pos, size_t len = npos);void swap(string& s);size_t find(char ch, size_t pos = 0);size_t find(const char* str, size_t pos = 0);string& operator+=(char ch);string& operator+=(const char* str);string substr(size_t pos = 0, size_t len = npos);void clear();private:size_t _size = 0;size_t _capacity = 0;char* _str = nullptr;const static size_t npos = -1;};ostream& operator<<(ostream& out, const string& s);istream& operator>>(istream& in, string& s);}

//test.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
using namespace std;//int main()
//{
//	//string s1("hello world");
//	//s1.erase(0, 4);
//	//cout << s1 << endl;//o world 从下标为0开始,删除4个字符
//	//s1.erase();
//	//cout << s1 << endl;//
//
//	//string s1("hello world");
//	//string s2;
//	//s1.replace(0, 1, "aaaa");
//	//cout << s1 << endl;//aaaaello world
//	string s1("hello world a b");
//	// 所有的空格替换为100%
//	size_t pos = s1.find(' ', 0);
//	while (pos != string::npos)
//	{
//		s1.replace(pos, 1, "100%");
//		// 效率很低,能不用就不要用了
//
//		pos = s1.find(' ', pos + 4);
//	}
//	cout << s1 << endl;//hello100%world100%a100%b
//
//	return 0;
//}//int main()
//{
//	string s1("hello world a b");
//	string s2;
//	for (auto ch : s1)
//	{
//		if (ch == ' ')
//		{
//			s2 += "100%";
//		}
//		else
//		{
//			s2 += ch;
//		}
//	}
//	s1.swap(s2);
//	cout << s1 << endl;//hello100%world100%a100%b
//
//	return 0;
//}//int main()
//{
//	string s1("hello");
//	string s2;
//	s2 = s1.substr(1, 2);
//	cout << s2 << endl;//el
//	cout << s1.substr(1) << endl;//ello
//
//	return 0;
//}//int main()
//{
//	//获取后缀名
//	string s1("Test.cpp");
//	string s2("Test.tar.zar");
//
//	size_t pos1 = s1.find('.');
//	size_t pos2 = s2.rfind('.');
//
//	if(pos1 != string::npos)
//	{
//		string s3 = s1.substr(pos1);
//		cout << s3 << endl;//.cpp
//
//		string s4 = s2.substr(pos2);
//		cout << s4 << endl;//.zar
//
//	}
//
//	return 0;
//}//int main()
//{
//	string s1("hello world");
//
//	size_t pos1 = s1.find_first_not_of("abcde");
//	cout << pos1 << endl;//0
//
//	pos1 = s1.find_last_not_of("h");
//	cout << pos1 << endl;//10
//
//
//	return 0;
//}#include"string.h"void print_str(const string& s)
{for (size_t i = 0; i < s.size(); i++){//s[i]++;cout << s[i] << endl;}string::const_iterator it = s.begin();while (it != s.end()){// *it = 'x';cout << *it << " ";++it;}cout << endl;}
void test_string1()
{//string s1("aabbcc");//构造成功//cout << s1.c_str() << endl;//for (size_t i = 0; i < s1.size(); i++)//{//	s1[i]++;//}//cout << s1.c_str() << endl;//string s2;cout << s2.c_str << endl;//string s1("aabbcc");//string::iterator it = s1.begin();//while (it != s1.end())//{//	cout << *it << " ";//	++it;//}//cout << endl;//a a b b c c//string s1("aabbcc");//for (auto ch : s1)//{//	cout << ch << " ";//}//cout << endl;//a a b b c c//string s3("hello");//print_str(s3);//bb cc dd//string s1("aabbcc ddeeff");//s1.push_back('a');//cout << s1.c_str() << endl;//string s2;//s2.push_back('a');//cout << s2.c_str() << endl;/*string s1("aabbcc ddeeff");s1.append("aaa");cout << s1.c_str() << endl;*///string s1("aabbcc ddeeff");//s1.insert(0, 'w');//cout << s1.c_str() << endl;//string s1("aabbcc ddeeff");//s1.insert(0, "ddd");//cout << s1.c_str() << endl;//string s2("aabbcc ddeeff");//s2.insert(12, "ddd");//cout << s2.c_str() << endl;//string s1("aabbcc ddeeff");//s1.erase(1, 2);//cout << s1.c_str() << endl;//string s1("aabbcc ddeeff");//string s2("abc");//s2.swap(s1);//cout << s1.c_str() << endl;//cout << s2.c_str() << endl;/*string s1("aabbcc ddeeff");cout << s1.find('\0') << endl;cout << s1.find('a',1) << endl;*///string s1("aabbcc ddeeff");//cout << s1.find("cc",0) << endl;//cout << s1.find('a', 1) << endl;//string s1("aabbcc ddeeff");//s1 += 'a';//cout << s1.c_str() << endl;//string s2("aabbcc ddeeff");//s2 += "bbb";//cout << s2.c_str() << endl;//string s1("aabbcc ddeeff");//string s2;//s2 = s1.substr(3, 4);//cout << s2.c_str() << endl;//string str;//string& s = str;//string s1("abcd");cout << s1 << endl;//string s2("acacac");//cout << s2 << endl;//string s1("abcabc");//cin >> s1;//cout << s1 << endl;/*string s1("hello world");cout << s1.c_str() << endl;cout << s1 << endl;s1.clear();cout << s1.c_str() << endl;cout << s1 << endl;*///string s1("abc");//cout << s1 << endl;//string s2(s1);//cout << s2 << endl;//string s1("aaaaaa");//string s3("xxxxxx");//s1 = s3;//cout << s1 << endl;//cout << s3 << endl;std::string str = std::to_string(123);cout << str << endl;std::string str1 = std::to_string(123.222);cout << str1 << endl;std::string str2 = std::to_string(123);int i = stoi(str2);cout << i << endl;}
int main()
{test_string1();return 0;
}

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

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

相关文章

网络通信---TCP协议1

今日内容 三次握手: 指建立tcp连接时&#xff0c;需要客户端和服务端总共发送三次报文确认连接。 四次挥手&#xff1a; 断开一个tcp连接&#xff0c;需要客户端和服务端发送四个报文以确认断开。 编程模型 TCP报文 客户端 服务端

Charles实战(三)

第一章节&#xff1a;过滤 Filter Focus Recording Settings - Include Filter Focus 第二章&#xff1a;重发 简单重发&#xff1a;鼠标右键- Repeat 简单压力&#xff1a; 鼠标右键 - Repeat Advanced Iterations:重复发送多少次 20 Concurrency:每次发几组请求&#x…

23 Python常用内置函数——map()

内置函数 map() 把一个函数 func 依次映射到序列或迭代器对象的每个元素上&#xff0c;并返回一个可迭代的 map 对象作为结果&#xff0c;map 对象中的每个元素是原序列中元素经过函数 func 处理后的结果&#xff0c;map() 函数不对原序列或迭代器对象做任何修饰。 print(map(…

数字图像处理和机器视觉中的常用特殊矩阵及MATLAB实现详解

一、前言 Matlab的名称来源于“矩阵实验室&#xff08;Matrix Laboratory&#xff09;”&#xff0c;其对矩阵的操作具有先天性的优势&#xff08;特别是相对于C语言的数组来说&#xff09;。在数字图像处理和机器视觉实践中&#xff0c;为了提高编程效率&#xff0c;MATLAB 提…

ResT v2 论文解读

paper&#xff1a;ResT V2: Simpler, Faster and Stronger official implementation&#xff1a;https://github.com/wofmanaf/ResT 出发点 ResTv2的设计目标是改进先前版本ResTv1的结构&#xff0c;以提高模型的效率和性能。ResTv1通过引入多尺度注意力机制&#xff08;EMS…

深入源码:解析SpotBugs静态代码分析框架 0

文章目录 引言SpotBugs概述启动附录 引言 SpotBugs是一个开源的Java静态分析工具&#xff0c;旨在帮助开发人员检测Java代码中的潜在缺陷和漏洞。以下是对SpotBugs的详细解释&#xff1a; SpotBugs概述 定义与功能&#xff1a;SpotBugs是FindBugs的继任者。FindBugs是一个广受…

甲方产品过于平庸该如何编写策划案?

面对甲方产品相对平庸的情况&#xff0c;作为策展新人&#xff0c;你需要发挥创意和策略思维&#xff0c;通过巧妙的策划来挖掘和呈现产品的独特价值&#xff0c;让观众在展馆中依然能找到吸引他们的亮点。 以下是一些建议&#xff0c;希望能帮助你编写出既真实又能吸引眼球的…

基于JSP、java、Tomcat、mysql三层交互的项目实战--校园交易网(2)登录,注册功能实现

技术支持&#xff1a;JAVA、JSP 服务器&#xff1a;TOMCAT 7.0.86 编程软件&#xff1a;IntelliJ IDEA 2021.1.3 x64 登陆页面如下 在这个页面中我们实现了一个登录页面和一个注册页面的Jsp文件&#xff0c;和两个java 的服务层文件 分别是web包下的denglu.jsp和zhuce.jsp以…

【Django】js实现简单计算器

文章目录 完整html写script写views写urls ##需求 ##实验 完整html {% load static %} <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, i…

【JUC】Java锁介绍

文章目录 阿里锁开发规范乐观锁和悲观锁悲观锁乐观锁 synchronized 类锁、对象锁synchronized有三种应用方式锁相关的8种案例演示&#xff08;对象锁、类锁&#xff09;标准访问ab两个线程&#xff0c;请问先打印邮件还是短信&#xff1f;sendEmail钟加入暂停3秒钟&#xff0c;…

c++入门----类与对象(中)

OK呀&#xff0c;家人们承接上文&#xff0c;当大家看过鄙人的上一篇博客后&#xff0c;我相信大家对我们的c已经有一点印象了。那么我们现在趁热打铁再深入的学习c入门的一些知识。 类的默认成员函数 首先我们学习的是我们的默认函数。不知道大家刚读这个名词是什么反应。默认…

鱼哥好书分享活动第27期:看完这篇《云原生安全》了解云原生环境安全攻防实战技巧!

鱼哥好书分享活动第27期&#xff1a;看完这篇《云原生安全》了解云原生安全攻防实战技巧&#xff01; 主要内容&#xff1a;读者对象&#xff1a;本书目录&#xff1a;了解更多&#xff1a;赠书抽奖规则: 当前全球数字化的发展逐步进入深水区&#xff0c;云计算模式已经广泛应用…

【Linux C | 网络编程】简易进程池的实现详解(一)

进程池&#xff08;Process Pool&#xff09;是一种并发编程的模型&#xff0c;用于管理和复用多个进程&#xff0c;以提高系统的效率和性能。它主要解决的问题是减少因频繁创建和销毁进程而带来的性能开销&#xff0c;特别是在需要处理大量并发任务时尤为有效。 主要组成部分…

法律 | 法律人AI使用指南

原文&#xff1a;法律 | 法律人AI使用指南|法官|法院|文书|公司法_网易订阅 01 引言 过去半年多&#xff0c;我一直在尝试着用AI来辅助自己的各项法律工作&#xff0c;将AI融入自己的日常工作之中&#xff0c;并试图形成自身稳定的“法律AI”工作流。在此过程中&#xff0c;…

实时捕获数据库变更

1.CDC概述 CDC 的全称是 Change Data Capture &#xff0c;在广义的概念上&#xff0c;只要能捕获数据变更的技术&#xff0c;我们都可以称为 CDC 。我们目前通常描述的CDC 技术主要面向数据库的变更&#xff0c;是一种用于捕获数据库中数据变更的技术&#xff0c;CDC 技术应用…

【Plotly-驯化】一文教你学会画最美动态可视化的热力图:heatmap技巧

【Plotly-驯化】一文教你学会画最美动态可视化的热力图&#xff1a;heatmap技巧 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &#x1f387; 免费获取…

JS:JavaScript 简介

前言 在当今数字时代&#xff0c;JavaScript已然成为了现代Web开发的基石。从最初作为浏览器中的一个小型脚本语言&#xff0c;到如今成为驱动全球互联网的强大引擎&#xff0c;JavaScript的发展历程本身就是一个令人着迷的故事。 好了开始学习JS吧 1. 如果刚开始了解js&#…

智慧城管解决方案

1. 项目整体概述 智慧城管项目面临历史发展机遇&#xff0c;十九大提出以人为核心保障民生&#xff0c;推进新型城镇化。市民对政府服务有新诉求&#xff0c;同时云计算、物联网、移动互联网等技术迅速发展。 2. 传统城管业务模式问题 传统城管业务模式存在问题&#xff0c;…

leetcode106. 从中序与后序遍历序列构造二叉树,力扣105姊妹题

leetcode106. 从中序与后序遍历序列构造二叉树 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7…

【每日刷题】Day86

【每日刷题】Day86 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 118. 杨辉三角 - 力扣&#xff08;LeetCode&#xff09; 2. 数组中出现次数超过一半的数字_牛客题霸…