【C++】日期类Date(详解)

🔥个人主页:Forcible Bug Maker

🔥专栏:C++

目录

前言

日期类

日期类实现地图

获取某年某月的天数:GetMonthDay

检查日期合法,构造函数,拷贝构造函数,赋值运算符重载及析构函数

日期类的+=day和+day

日期类的-=day和-day

前置++和后置++

前置--和后置--

比大小运算符的重载

日期-日期返回天数

暴力++法

直接相减法

const成员

流插入和流提取重载

友元(friend)

结语


前言

本篇主要内容:日期类的实现

上篇我们介绍了拷贝构造函数和赋值运算符重载两大类的默认成员函数,本篇将会介绍更多关于操作符重载的实例运用。日期类,是与日期相关的类,主要用于处理与日期和时间相关的操作。我们将在完善一个日期类的过程中加深对运算符重载的理解和运用。在理解操作符重载之后,最后两个默认成员函数学习起来也就不是什么大问题了。

日期类

日期类实现地图

在实现日期类之前,需事先要知道要实现哪些内容。我会给出一份类的指南,也就是成员变量和成员函数的声明,然后根据声明一步步实现其中的成员函数。在代码编写过程中,成员函数是可以直接定义在类内部的;但是在实际开发过程中,考虑到工程级项目的规模,一般采用声明和定义分离的方式经行类的实现。将声明统一放在 Date.h 中,把成员函数的定义统一放在 Date.cpp 中,道理跟C语言的声明定义分离一样。

#include<iostream>
#include<cassert>
using namespace std;

class Date
{
	// 友元
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
public:
	// 获取某年某月的天数
	int GetMonthDay(int year, int month);
	// 检查日期是否合法
	bool CheckDate();
	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1);
	// 拷贝构造函数
  // d2(d1)
	Date(const Date& d);
	// 赋值运算符重载
  // d2 = d3 -> d2.operator=(&d2, d3)
	Date& operator=(const Date& d);
	// 析构函数
	~Date();
	// 日期+=天数
	Date& operator+=(int day);
	// 日期+天数
	Date operator+(int day);
	// 日期-天数
	Date operator-(int day);
	// 日期-=天数
	Date& operator-=(int day);
	// 前置++
	Date& operator++();
	// 后置++
	Date operator++(int);
	// 后置--
	Date operator--(int);
	// 前置--
	Date& operator--();
	// >运算符重载
	bool operator>(const Date& d);
	// ==运算符重载
	bool operator==(const Date& d);
	// >=运算符重载
	bool operator >= (const Date& d);
	// <运算符重载
	bool operator < (const Date& d);
	// <=运算符重载
	bool operator <= (const Date& d);
	// !=运算符重载
	bool operator != (const Date& d);
	// 日期-日期 返回天数
	int operator-(const Date& d);
	void Print() 
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

// 输出流重载
ostream& operator<<(ostream& out, const Date& d);
// 输入流重载
istream& operator>>(istream& in, Date& d);

这份地图中大家也许会发现很多陌生的内容,如友元,重载前置++和后置++,流插入和流提取重载等。不过不用着急,接下来都会讲到。

获取某年某月的天数:GetMonthDay

GetMonthDay函数用于获取某年某月的天数,由于其在日期加天数和减天数运算符重载的函数中被频繁调用,且代码量较少,我们可以直接将其设置为内联,定义到类的内部定义到类内部的成员函数都默认加了内联inline,而分离定义的成员函数没有此特性)。

注:分离声明和定义的函数是无法内联的

int GetMonthDay(int year, int month)
{
	assert(month > 0 && month < 13);
	int months[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };
   	if (month == 2 && (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)) {
	    return 29;
	}
	else return months[month];
}

由于此函数定义在类的内部,故没有 Date:: 来指定命名空间,此函数的其他逻辑应该也好理解,最终通过传过来的年和月来确定当月的天数,考虑到闰年判断等问题。

检查日期合法,构造函数,拷贝构造函数,赋值运算符重载及析构函数

检查日期是否合法,需要检查月不能小于1或者大于12,日要根据年和月来判断,见代码:

bool Date::CheckDate() // 由于声明和定义分离,定义函数时需指定一下命名空间Date::
{
	if (_month < 1 || _month > 12
		|| _day < 1 || _day > GetMonthDay(_year, _month)) {
		return false;
	}
	else return true;
}

构造函数,拷贝构造以及赋值重载等没什么好说的,注意拷贝构造需判断一下日期是否合法:

// 全缺省的构造函数
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
	if (!CheckDate()) {
		cout << "日期非法\n" << endl;
	}
}

// 拷贝构造函数
// d2(d1)
Date::Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}

// 赋值运算符重载
 // d2 = d3 -> d2.operator=(&d2, d3)
Date& Date::operator=(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
	return *this;
}

// 析构函数
Date::~Date()
{
	_year = 0;
	_month = 0;
	_day = 0;
}

日期类的+=day和+day

日期类可以+吗?答案是肯定的,不过不是两个日期相加,而是一个日期去+一个天数,如,今天是2024/4/20,加上5就是五天后,五天后是2024/4/25。如何实现+=,来看看代码:

// 日期+=天数
Date& Date::operator+=(int day)
{
    // 此处是对+的day为负时的处理
	if (day < 0) {
		*this -= (-day); // 复用了-=,下文会讲
		return *this;
	}
	_day += day;
	while (_day > GetMonthDay(_year, _month)) {
		_day -= GetMonthDay(_year, _month);
		++_month;
		if (_month == 13) {
			++_year;
			_month = 1;
		}
	}
	return *this;
}

如果day为大于0的数,首先将day的值加到成员变量_day上,然后循环判断_day是否大于当月天数,如果大于,就减去当月天数,_month+1,_year根据_month是否大于12判断自增;如果_day小于当月天数,则跳出循环。最后返回值是为了贴合内置类型连续运算赋值的规则,如,a=b+=c;而Date&引用返回则是为了减少拷贝

写道这里,就即将到类和对象一个神奇的使用方式了,它的名字叫——复用

我们可以直接复用+=来实现+,来看看具体的复用代码:

// 日期+天数
Date Date::operator+(int day)
{
	Date tmp(*this);
	tmp += day; // 复用+=
	return tmp;
}

日期+day的规则是不能改变运算日期的值,所以这里在成员函数中定义了一个tmp拷贝,用来执行运算操作,最后传值返回,是因为tmp作为临时变量,出了函数就会销毁。

注:这里提供的是+=复用+的设计模式。实际上,用+复用+=也是可行的,但是这种复用方式却比+=复用的质量差,大家感兴趣可以自行实现并考虑其中原因。

日期类的-=day和-day

-=day虽然思路和+=差不多,但是逻辑却比+=难搞一些,建议仔细思考后在上手写。

// 日期-=天数
Date& Date::operator-=(int day)
{
    // 当减的天数为负时的操作
	if (day < 0) {
		*this += (-day);// 复用了刚才写的+=
		return *this;
	}
	_day -= day;
	while (_day < 1) {
		--_month;
		if (_month == 0) {
			--_year;
			_month = 12;
		}
		day += GetMonthDay(_year, _month);
	}
	return *this;
}

在给_day+=天数时,注意加的是上个月的天数,并非本月天数。写了-=,-的实现也就是简单的复用操作了:

// 日期-天数
Date Date::operator-(int day)
{
	Date tmp(*this);
	tmp -= day;
	return tmp;
}

返回值是否引用返回和+=day和+day是同理的。

前置++和后置++

知道内置类型的前置++和后置++吗?如++a,a++等,它们的作用都是给变量a自增1,学了这么长时间,你是否对它们的区别了如指掌。本篇我们讲的是自定义类型的自增,如,日期类,我们要给一个自定义类型(日期类)自增,但计算机并不知道日期自增的规则,这时就需要人为提供内置类型的自增运算符。其实,上面刚刚讲过复用,我们直接复用+=和-=就可以了,你想想,什么是++?什么是--?不就是+=1和-=1嘛!

// 前置++:返回+1之后的结果
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

注:this指向的对象函数结束后不会销毁,故以引用方式返回提高效率

如果不提供参数,在C++的定义之下,默认就是放到对象前面的重载运算符:++d,但如果单将一个运算符放到对象后面构成运算符重载应该怎么办呢?看看C++提供的解决方式:

// 后置++:自增,返回自增之前的拷贝
Date Date::operator++(int)
{
	Date tmp(*this);
	*this += 1;
	return tmp;
}

前置++和后置++都是一元运算符,为了可以让前置++和后置++形成正确重载,C++规定后置++重载时多增加一个int类型的参数,但调用参数时该参数不用传递,编译器自动传递

注:后置++是先使用后+1,因此只需要返回+1前的值,故需要先将this保存一份,然后给this+1。而代码中的tmp是临时对象,因此只能以值得方式返回,而不能返回引用

前置--和后置--

不想多说了,四个字——同理,复用

// 前置--
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}

// 后置--
Date Date::operator--(int)
{
	Date tmp(*this);
	*this -= 1;
	return tmp;
}

注意区分前置和后置的区别,控制下返回值是否引用返回就行。

比大小运算符的重载

为什么要给日期提供比大小重载,因为内置类型无法完成比较日期的任务。比大小需要提供的重载函数就多了,包括 <,<=,==,>,>=,!= ,一套写下来,岂不是能把人累瘫,别着急,实际上,需要你完成的实际上只有两个,> 和 ==,当然你选择 < 和 ==,或者 <,!= 统统都可以,如果还没想通,没关系,来看看我是如何实现的,这里以> 和 ==为例。

// >运算符重载
bool Date::operator>(const Date& d)
{
	if (_year > d._year
		|| _year == d._year && _month > d._month
		|| _year == d._year && _month == d._month && _day > d._day) return true;
	return false;
}

// ==运算符重载
bool Date::operator==(const Date& d)
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}

这里是对于>和==的重载,其中逻辑不难理解。

此时如果我们想要实现 >= ,直接复用上面两个重载就可以了。

// >=运算符重载
bool Date::operator>=(const Date& d)
{
	return *this > d || *this == d;
}

发现C++运算符重载和复用的魅力了吗?

如果此时你需要一个 < 重载:

// <运算符重载
bool Date::operator<(const Date& d)
{
	return !(*this > d || *this == d);
}

如果此时你需要一个 <= 重载:

// <=运算符重载
bool Date::operator<=(const Date& d)
{
	return !(*this > d);
}

如果此时你需要一个  != 重载:

// !=运算符重载
bool Date::operator!=(const Date& d)
{
	return !(*this == d);
}

如果……哦,已经没有如果了,这就是所有的比大小运算符重载🙂,很有意思吧。

日期-日期返回天数

日期减日期为的是计算两个日期之间的天数间隔。对于日期相减,这里提供了两种实现方案。

暴力++法

找出日期中小的那个,然后通过记录每次++的次数n来记录两日期之间的间隔,同时设置一个变量flag来记录两个日期之间的差是正的还是负的。

// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
	Date max = *this;// 假设大的那个是*this
	Date min = d;
	int flag = 1;
	int n = 0;
	if (*this < d) { //判断并重置max和min以及日期间隔正负
		max = d;
		min = *this;
        flag = -1;
	}
	while (min != max) {
		++min;
		++n;
	}
	return n * flag;
}

此方法也是最好理解的一种,虽然暴力++会有一些消耗,但是对于目前计算机的算力来说却是微不足道的。

直接相减法

这个过程就稍稍有些复杂,你可以先确定max(大日期对象)下一年的第一天tmpmaxmin(小日期对象)本年的第一天tmpmin,让它们的差值✖365,加到 n 上,同时遍历一遍这些年,找到一个闰年就让n+1。最后定义两个整型变量(tmp1,tmp2),让tmpmin逐次++(++使用的是之前重载的日期类++,最好用前置++,减少拷贝的消耗),同时用tmp1计数,直到和min相等让max逐次++,同时tmp2计数,直到和tmpmax相等。这时让n减去tmp1和tmp2后,得到的就是两个日期之间的差值了。

以下是实现代码,亲测正确:

int Date::operator-(const Date& d)
{
	Date max = *this;
	Date min = d;
	int flag = 1;
	int n = 0;
	if (*this < d) {
		max = d;
		min = *this;
		flag = -1;
	}
    // 以上是比较日期确定max和min
	n += (max._year - min._year + 1) * 365;
	for (int i = min._year; i <= max._year; i++)
		if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0)
			++n;
    // 以上是根据年计算间隔的天数
	Date tmpmax(max._year + 1, 1, 1);int tmp1 = 0;
	Date tmpmin(min._year, 1, 1);int tmp2 = 0;
	while (tmpmax != max) {
		++max;
		++tmp1;
	}
	while (tmpmin != min) {
		++tmpmin;
		++tmp2;
	}
    // 以上是日期矫正,计算tmp1和tmp2
	n -= tmp1;
	n -= tmp2;
	return n * flag;
}

对于日期相减,不止有这两种实现,大家想到一些别的方式也可以自己亲自试一试,还是很有意思的。

const成员

将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改

具体怎么修饰呢?写一个const在参数列表后面:

在()括号后放const是将隐式传递的*this指针类型变成了const *this指针类型,这种解决方案是为了应对*this无法被显示改变为const类型而产生的。

对于const类型的对象,和内置类型的const修饰规则非常相似,权限只能平移和缩小,而不能放大。看看代码案例:

const Date d1;
Date& d2 = d1;// 不支持,d2是Date类型,取d1的引用属权限放大
const Date& d3 = d1;//支持,权限平移

Date d4;
const Date& d5 = d4;// 支持,权限缩小

对于const成员函数内部,是不可以调用非const成员函数的;而非const成员函数却可以调用其他的const成员函数

所以,对于一些不会改动Date对象数据的成员函数,尽量提供const类型的成员函数即可,如下:

// 获取某年某月的天数const版
int GetMonthDay(int year, int month)const
{
	assert(month > 0 && month < 13);
	int months[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };
	if (month == 2 && (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)) {
		return 29;
	}
	else return months[month];
}

GetMonthDay定义在类内部,故不需要限定命名空间。

// 检查日期是否合法const版
bool Date::CheckDate()const
{
	if (_month < 1 || _month>12
		|| _day < 1 || _day>GetMonthDay(_year, _month)) {
		return false;
	}
	else return true;
}

基本上就是在函数()后加上const即可,需要这样调整的函数还包括比大小重载函数,日期相减函数,-day和+day,Print打印日期函数等等,这里就不一一列举了。

流插入和流提取重载

大家之前可能接触过C语言,这里就能体现出C语言输入输出的局限性了,它没办法支持对象类型的输入输出。在C++标准库<iostream>(包含istream类和ostream类)中,内含了输入流对象cin和输出流对象cout,通过使用这两个对象,我们可以支持输出所有的内置类型变量。今天要讲的流插入和流提取重载,就是可以帮助大家直接用cin和cout支持内置类型的输入输出。

如果需要定义一个流插入的重载,你会如何定义呢?

void Date::operator<<(ostream& out)
{
    cout << _year << "-" << _month << "-" <<_day <<endl;
}

是这样吗?那就大错特错了,按照运算符重载规则,

cout << d;

这种书写方式明显不符合重载时的参数顺序,所以如果想要调用上面这份重载,需要这样写:

d << cout;

但是,这种使用方式明显违背了像内置类型那样使用输入输出流的初衷。产生这种问题的主要原因还是无法改变调用类内部定义的成员函数时第一个传过去的元素永远是this指针

为解决这样的问题,需要我们把流插入和流提取的函数重载在类的外部,像下面这样:

ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}

这里返回一个对象引用类型是为了贴合内置类型的使用规则,连续输出,如cout << a << b << c;如果没有此返回值,那么使用对象时,就只能用一次cout打印一个Date对象,如cout << d;而不是cout << d1 << d2 << d3;。

流提取也是同样的方法:

istream& operator>>(istream& in, Date& d)
{
	cout << "请输入年月日,用空格分隔:";
	in >> d._year >> d._month >> d._day;
	if (!d.CheckDate()) {
		cout << "日期非法\n" << endl;
	}
	return in;
}

返回一个对象的引用也是为了贴合内置类型使用规则。

到这里,你不免会问,如果将重载函数定义在了类的外部,那么该如何使用类内部定义的私有成员变量,如_year,_month,_day呢?别急,接下来补一下之前挖的坑,友元。

友元(friend)

在C++中,友元(Friend)是一个特殊的机制,它允许一个非成员函数或者一个类(或类的成员函数)访问另一个类的私有(private)或保护(protected)成员。友元不是类的成员,但它可以访问类的所有成员,包括私有和保护成员。这种访问权限的赋予是通过在类的定义中使用friend关键字来实现的。只需要在类的内部添加上类外定义的函数的声明,并在声明前加上关键字friend即可,一般这种友元函数允许写在类内部的任意地方,一般来说会把它放在整个类的开头。当一个函数成为一个类的友元,那么这个函数内部就可以随意使用类中的私有(private)或保护(protected)成员了

class Date
{
	// 友元
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
public:
    //。。。
private:
    //。。。
}

结语

本篇博客实现了日期类Date,加深对运算符重载的运用,讲了前置++和后置++:传一个改变成后置++样式的int;还讲到const成员:由于无法改变*this类型而添加的const;流插入和流提取重载:由于无法改变传参顺序而定义到类的外部等等。这篇博客也算是对之前学到类和对象内容的一个阶段性的应用和总结吧。

博主后续还会产出更多有意思的内容,感谢大家的支持!♥

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

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

相关文章

2. uni-app的一些介绍

前言 就目前的前端生态而言&#xff0c;跨端开发基本算是每一个前端开发者必备的技能点之一了&#xff0c;而在Vue这个技术栈里uni-app在跨端是独一档的&#xff0c;不信的话可以翻翻Boss之类的招聘网站.... 概述 阅读时间&#xff1a;约5~10分钟&#xff1b; 本文重点&…

linux的编译器vim

vim简介 之前我们在win下写代码&#xff0c;都是下载一些编译器VS/eclipse等 他们不仅可以写代码&#xff0c;还可以实现代码的运行调试&#xff0c;开发。这样的编译器叫做集成编译器 而linux中虽然也有这样的编译器&#xff0c;但不管是从下载&#xff0c;还是使用中都会显…

谷歌地球引擎Google Earth Engine下载数字高程模型DEM数据的方法

本文介绍在谷歌地球引擎&#xff08;Google Earth Engine&#xff0c;GEE&#xff09;中&#xff0c;批量下载指定时间与空间范围内的数字高程模型&#xff08;DEM&#xff09;数据的方法。 本文是谷歌地球引擎&#xff08;Google Earth Engine&#xff0c;GEE&#xff09;系列…

UltraScale+的40G/50G Ethernet Subsystem IP核使用

文章目录 前言一、设计框图二、模块说明三、上板3.1、发送端3.1、接收端 四、总结 前言 上文介绍了10G/25G Ethernet Subsystem IP核使用&#xff0c;本文将在此基础上介绍40G/50G Ethernet Subsystem IP核的使用&#xff0c;总体区别不大。 一、设计框图 由于40G以太网需要…

嵌入式 - i.MX93 Evaluation Kit介绍

MCIMX93-EVK (i.MX 93 APPLICATIONS PROCESSOR) 1, Out of the Box [ 开箱 ] Top view i.MX 93 11x11 EVK board Back view: Board kit contents: (board, power supply, cable, software, Documentation) MCIMX93-EVK board assembled with two separate boards, MCIMX93-SOM…

《MATLAB科研绘图与学术图表绘制从入门到精通》示例:绘制伊甸火山3D网格曲面图

11.4.2小节我们使用3D曲面图可视化分析伊甸火山数据&#xff0c;本小节我们采用3D网格曲面图可视化分析伊甸火山数据&#xff0c;以展示其地形&#xff0c;具体示例代码如下。 购书地址&#xff1a;https://item.jd.com/14102657.html

RabbitMQ项目实战(一)

文章目录 RabbitMQ项目实战选择客户端基础实战 前情提要&#xff1a;我们了解了消息队列&#xff0c;RabbitMQ的入门&#xff0c;交换机&#xff0c;以及核心特性等知识&#xff0c;现在终于来到了激动人心的项目实战环节&#xff01;本小节主要介绍通过Spring Boot RabbitMQ S…

HackMyVM-Hommie

目录 信息收集 arp nmap WEB web信息收集 dirsearch ftp tftp ssh连接 提权 系统信息收集 ssh提权 信息收集 arp ┌──(root㉿0x00)-[~/HackMyVM] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 08:00:27:77:ed:84, IPv4: 192.168.9.126 Starting arp-…

PhpStorm2024安装包(亲测可用)

目录 一、软件简介 二、软件下载 一、软件简介 PhpStorm是由JetBrains公司开发的一款商业的PHP集成开发环境&#xff08;IDE&#xff09;&#xff0c;深受全球开发人员的喜爱。它旨在提高开发效率&#xff0c;通过深刻理解用户的编码习惯&#xff0c;提供智能代码补全、快速导…

14.哀家要长脑子了!

目录 1.598. 区间加法 II - 力扣&#xff08;LeetCode&#xff09; 2.419. 甲板上的战舰 - 力扣&#xff08;LeetCode&#xff09; 3.54. 螺旋矩阵 - 力扣&#xff08;LeetCode&#xff09; 4. 498. 对角线遍历 - 力扣&#xff08;LeetCode&#xff09; 5. 566. 重塑矩阵 - …

希亦、添可、追觅洗地机哪一款更好用?口碑洗地机型号多维度测试

近年来&#xff0c;随着“懒人经济”的兴起&#xff0c;商家们纷纷推出各种智能化、便捷化、高效化的家电产品&#xff0c;以提升人们的生活品质。在这些家电产品中&#xff0c;家居清洁领域的小家电发展尤为迅速&#xff0c;产品不断更新换代。在众多清洁家电产品中&#xff0…

C++ | Leetcode C++题解之第41题缺失的第一个正数

题目&#xff1a; 题解&#xff1a; class Solution { public:int firstMissingPositive(vector<int>& nums) {int n nums.size();for (int i 0; i < n; i) {while (nums[i] > 0 && nums[i] < n && nums[nums[i] - 1] ! nums[i]) {swap(…

[svelte]属性和逻辑块

属性 / Default values • Svelte 教程 | Svelte 中文网 属性 Declaring props 到目前为止&#xff0c;我们只处理了内部状态——也就是说&#xff0c;这些值只能在给定的组件中访问。 在任何实际应用程序中&#xff0c;都需要将数据从一个组件向下传递到其子组件。为此&…

Java测试编程题

题目1 1.创建5个线程对象 线程名设置为&#xff08;Thread01&#xff0c;Thread02&#xff0c;Thread03&#xff0c;Thread04&#xff0c;Thread05&#xff09;使用 代码实现5个线程有序的循环打印&#xff0c;效果如下&#xff1a; Thread01正在打印1 Thread02正在打印2 Threa…

OpenHarmony多媒体-mp3agic

简介 mp3agic 用于读取 mp3 文件和读取/操作 ID3 标签&#xff08;ID3v1 和 ID3v2.2 到 ID3v2.4&#xff09;,协助开发者处理繁琐的文件操作相关&#xff0c;多用于操作文件场景的业务应用。 效果展示&#xff1a; 下载安装 ohpm install ohos/mp3agicOpenHarmony ohpm环境配…

【Day 4】Maven + Spring入门 + HTTP 协议

开始学后端&#xff01; 1 Maven Maven 是一款用于管理和构建 Java 项目的工具&#xff0c;基于项目对象模型(POM)的概念&#xff0c;通过一小段描述信息来管理项目的构建。 作用&#xff1a; 依赖管理 方便快捷的管理项目依赖的资源(jar 包)&#xff0c;避免版本冲突问题 …

接雨水 , 给定二维图,能容多少水

42. 接雨水 - 力扣&#xff08;LeetCode&#xff09; 看着就是非常常规的题目&#xff0c;所以非常有必要掌握。 最少也把O&#xff08;n^2&#xff09;的方法写出来吧。力扣官方题解的三种方法O&#xff08;n&#xff09;都挺好&#xff0c;不过可能有点难读&#xff0c;在此…

简单的LRU本地缓存实现-Java版本

文章目录 什么是缓存缓存的种类缓存的关键特性缓存的优势与挑战优势&#xff1a;挑战&#xff1a; 缓存的应用场景什么是LRUCacheLRU 缓存的工作原理核心操作为何选择 LRU使用场景 一个简单的LRU缓存实现相关资料基础资料 什么是缓存 缓存&#xff08;Cache&#xff09;是一种…

机器人课程教师面对的困境有哪些(补充)

唯有自救&#xff0c;唯有自强&#xff0c;方能有希望。 前序 距离这一篇博文发表已经快2年了…… 机器人课程教师面对的困境有哪些 至少从5年前就已经有需求减少&#xff0c;供给过剩的现象出现了。 为何在2019年之后应用型本科开设ROS课程优势消逝 案例 博客分享过工作…

VSCode 目录折叠展开、缩进深度设置

1、VSCode 目录折叠展开设置 运行 Visual Studio Code &#xff0c;按 Ctrl &#xff0c;打开设置 输入Explorer:Compact Folders&#xff0c;取消勾选 或者在设置文件上添加 "explorer.compactFolders": false2、VSCode 目录缩进深度设置 输入Workbench Tree:…