c++学习笔记-提高编程-模板(哔站-黑马程序员c++教学视频)

这篇具有很好参考价值的文章主要介绍了c++学习笔记-提高编程-模板(哔站-黑马程序员c++教学视频)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1、模板概念

2、模板特点

3、模板语法

3.1编程思想:泛型编程

3.2两种模板方法:

3.2.1 函数模板

3.2.2 类模板


1、模板概念

通用的模具,提高代码复用性

2、模板特点

不可以直接使用,只是一个框架;模板的通用性并不是万能的。

3、模板语法

3.1编程思想:泛型编程

3.2两种模板方法:

3.2.1 函数模板

函数模板的作用:建立一个通用函数,其函数返回值类型和参数类型可以不具体确定,用一个虚拟的类型来代表。

1)语法:


template<typename T>//函数声明或定义

函数


template——声明创建函数模板

typename——表明其后面的符号是一种类型,可以用class替代

T——通用的数据类型,名称可以替换,通常为大写字母

2)代码示例:

#include<iostream>
using namespace std;

//传统方法
//整型两个整型函数

void swapInt(int& a, int& b)
{
	int temp = a;
	a = b;
	b = temp;
}

//交换两个浮点型
void swapDouble(double& a, double& b)
{
	double temp = a;
	a = b;
	b = temp;
}

//函数模板
template<typename T>//声明一个模板,告诉编译器后面的代码中紧跟着的T不要报错,T是一个通用数据类型
void mySwap(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}

void test01()
{
	int a = 10;
	int b = 20;

	swapInt(a, b);
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	double c = 30.33;
	double d = 40.1;

	swapDouble(c, d);
	cout << "c = " << c << endl;
	cout << "d = " << d << endl;
}

void test02()
{
	int a = 10;
	int b = 20;
	//利用函数模板交换
	//两种方式使用
	//1、自动类型推到
	mySwap(a, b);


	//2、显示指定类型
	mySwap<int>(a, b);//<>中指定T的类型

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

}

int main()
{
	test02();

	system("pause");
	return 0;
}

3)总结:

  • 函数模板利用关键字Template
  • 使用函数模板有两种方法:自动推导类型、显示指定类型
  • 模板的目的是为了提高代码复用性,将类型参数化

4)注意事项:

  • 自动类型推导,T必须推导出一致的数据类型
  • 模板必须要确定出T的类型,才可以使用

5)案例-选择排序

#include<iostream>
using namespace std;

//实现通用的对数组进行排序的函数
//规则 从大到小
//算法 选择排序
//测试 char 数组、int数组

//交换模板
template<typename T>
void mySwap(T& a, T& b)
{
	T temp;
	temp = a;
	a = b;
	b = temp;
}

//排序模板
template<typename T>
void mySort(T arr[],int len)
{
	for (int i = 0; i < len; i++)
	{
		int max = i;//认定最大值的下标
		for (int j = i + 1; j < len; j++)
		{
			//认定的最大值 比 遍历的j下标要小,说明j下标的元素才是真的最大值
			if (arr[max] < arr[j])
			{
				max = j;
			}
		}
		if (max != i)
		{
			//交换这两个元素
			mySwap(arr[i], arr[max]);
		}

	}

}

//打印数组的模板
template<typename T>//typename和class可相互替换
void printArray(T arr[],int len)
{
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
}

void test01()
{
	char charArr[] = "badcfe";
	int len = sizeof(charArr) / sizeof(char)-1;
	mySort(charArr, len);
	printArray(charArr, len);
	
}


void test02()
{
	int intArr[] = { 1,4,3,6,3,8,2,10 };
	int len = sizeof(intArr) / sizeof(int);
	mySort(intArr, len);
	printArray(intArr, len);
}

int main()
{
	test01();
	test02();
	system("pause");
	return 0;
}

6)普通函数和函数模板的区别:普通函数可以发生隐式类型转换,但函数模板只有显示类型推导时,可以发生隐式类型转换

#include<iostream>
using namespace std;

//1、普通函数调用可以发生隐式类型转换
//2、函数模板 用自动类型推导,不可以发生隐式类型转换
//3、函数模板 用显示类型推导,可以发生隐式类型转换

//普通函数
int myAdd01(int a, int b)
{
	return a + b;
}

template<typename T>
int myAdd02(T a, T b)
{
	return a + b;
}

void test01()
{
	int a = 10;
	int b = 20;
	char c = 'c';//把字符型变量转换为整型。ASCII,a-97,c-99,
	cout << myAdd01(a, c) << endl;

	//cout << myAdd02(a, c) << endl;//自动推导类型!错误示例
	cout << myAdd02<int>(a, c) << endl;
}
int main()
{
	test01();
	system("pause");
	return 0;
}

 7)普通函数和函数模板的调用规则:

结论:如果创建了函数模板,就别多此一举创建普通函数了,OK?

  • 如果同时存在普通函数和模板函数,优先调用普通函数
  • 函数模板也存在函数重载
  • 可以使用空模板参数列表  强制调用 模板函数
  • 如果调用模板函数可以产生更好的效果,优先调用模板函数
#include<iostream>
using namespace std;

//普通函数与函数模板调用规则
//1、如果普通函数和模板函数都可以调用,优先调用普通函数
//2、可以通过空模板参数列表  强制调用  函数模板
//3、函数模板可以发生函数重载
//4、如果函数模板可以产生更好的匹配,优先调用函数模板

void myPrint(int a, int b)
{
	cout << "调用普通函数" << endl;
}

template<class T>
void myPrint(T &a, T &b)
{
	cout << "调用模板" << endl;
}

template<class T>
void myPrint(T a, T b,T c)
{
	cout << "调用 重载模板" << endl;
}

void test01()
{
	int a = 10;
	int b = 10;
	//myPrint(a, b);

	通过空模板的模板参数列表,强制调用函数模板
	//myPrint<>(a, b);

	函数模板也可以发生重载
	//myPrint<>(a, b,100);

	//如果函数模板产生更好的匹配,优先调用函数模板
	char c1 = 'a';
	char c2 = 'c';
	myPrint(c1, c2);
}
int main()
{
	test01();
	system("pause");
	return 0;
}

 8)模板的局限性

c++学习笔记-提高编程-模板(哔站-黑马程序员c++教学视频)

 模板并不是万能的,有些特定的数据类型,需要具体化方式做特殊实现

#include<iostream>
using namespace std;

//模板的局限性
//模板并不是万能的,有些特殊数据类型,需要具体化方式做特殊实现

class Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	string m_Name;
	int m_Age;
};

//对比两个数据是否相等
template<class T>
bool myCompare(T& a, T& b)
{
	if (a == b)
	{
		return true;
	}
	else
	{
		return false;
	}
}

//利用具体化PersomyComparen的版本,具体化优先调用
template<>bool myCompare(Person& p1, Person& p2)
{
	if (p1.m_Name==p2.m_Name && p1.m_Age == p2.m_Age)
	{
		return true;
	}
	else
	{
		return false;
	}
}

void test01()
{
	int a = 10;
	int b = 20;

	bool ret = myCompare(a, b);

	if (ret)
	{
		cout << "a == b" << endl;
	}
	else
	{
		cout << "a != b" << endl;
	}

}
void test02()
{
	Person p1("Tom", 10);
	Person p2("Tom",20);

	bool ret = myCompare(p1, p2);

	if (ret)
	{
		cout << "p1 == p2" << endl;
	}
	else
	{
		cout << "p1 != p2" << endl;
	}

}

//
int main()
{
	//test01();
	test02();
	system("pause");
	return 0;
}

3.2.2 类模板

建立一个通用类,类中成员  数据类型可以不具体制定,用一个虚拟的类型来代替

1)类模板语法


template <typename T>


template——声明创建模板

typename——表明其后面的符号是一种类型,可以用class替代

T——通用的数据类型,名称可以替换,通常为大写字母

#include<iostream>
using namespace std;

//模板类


template<class NameType,class AgeType>
class Person
{
public:
	Person(NameType name, AgeType age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	void ShowPerson()
	{
		cout << "name:  " << this->m_Name << " age:  "<<this->m_Age << endl;
	}
	NameType m_Name;
	AgeType m_Age;
};


void test01()
{
	Person<string, int>p1("Susan", 99);//<string, int>模板参数列表
	p1.ShowPerson();

}

int main()
{
	test01();
	system("pause");
	return 0;
}

2)类模板和函数模板的区别

  • 类模板没有自动类型推导的使用方式
  • 类模板在模板的参数列表中,可以有默认参数
#include<iostream>
using namespace std;

//模板类和函数模板的区别
//1、类模板没有自动类型推导的使用方式
//2、类模板在模板的参数列表中,可以有默认参数


//template<class NameType, class AgeType >//没默认参数
template<class NameType, class AgeType = int>//类模板可以有默认参数
class Person
{
public:
	Person(NameType name, AgeType age)
	{
		this->m_name = name;
		this->m_age = age;
	}

	void ShowPerson()
	{
		cout << "姓名:" << this->m_name << "  年龄:" << this->m_age << endl;
	}

	NameType m_name;
	AgeType m_age;
};



void test01()
{
	//Person p1("Susan", 18);//无法自动推导!错误示例

	//无默认参数的调用
	Person<string, int> p1("Susan", 18);//只能显示指定类型,正确示例
	p1.ShowPerson();
}

void test02()
{
	//有默认参数的调用
	Person<string>  p("Tom", 999);
	p.ShowPerson();
}

int main()
{
	test02();
	system("pause");
	return 0;
}

3)类模板中成员函数的调用时机

  • 普通类中的成员函数在一开始就可以创建
  • 类模板中的成员函数在调用时才可以创建
#include<iostream>
using namespace std;

//类模板中的成员函数的创建时机
//普通类中的成员函数一开始就可以创建
//类模板中的成员函数在调用时才可以创建

class Person1
{
public:
	void showPerson1()
	{
		cout << "Person1 show" << endl;
	}
};

class Person2
{
public:
	void showPerson2()
	{
		cout << "Person2 show" << endl;
	}
};

template<class T>
class MyClass
{
public:
	T obj;

	//类模板中的成员函数,并不是一开始就创建,而是在模板调用时再生成
	void func1()
	{
		obj.showPerson1();
	}
	void func2()
	{
		obj.showPerson2();
	}
};

void test01()
{
	MyClass<Person1>m;
	m.func1();
	//m.func2();//编译会出错,说明函数调用才会去创建成员函数
}

int main()
{
	test01();
	system("pause");
	return 0;
}

4)类模板对象做函数参数

类模板实例化出的对象,向函数传参的方式共三种:

  • 指定传入的类型 ---  直接显示对象的数据类型
  • 参数模板化        ---将对象的参数变为模板后进行传递
  • 整个类模板化   ---将这个对象类型 模板化进行传递
#include<iostream>
#include<string>
using namespace std;

//类模板对象做函数参数
//1、指定传入的类型
//2、参数模板后
//3、整个类模板化

template<class T1,class T2>
class Person
{
public:
	Person(T1 name, T2 age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	void showPerson()
	{
		cout << "姓名:" << this->m_Name << "  年龄:" << this->m_Age << endl;
	}

	T1 m_Name;
	T2 m_Age;
};

//1、指定传入的类型
void printPerson(Person<string, int>&p)
{
	p.showPerson();
}
void test01()
{
	Person<string, int>p("Susan", 18);
	printPerson(p);
	
}

//2、将参数模板化
template<class T1,class T2>
void printPerson2(Person<T1,T2>&p)
{
	p.showPerson();
	cout << "T1 的类型:" << typeid(T1).name() << endl;
	cout << "T2的类型:" << typeid(T2).name() << endl;

}
void test02()
{
	Person<string, int>p("Tom", 98);
	printPerson2(p);

}

//3、整个类模板化
template<class T>
void printPerson3(T &p)
{
	p.showPerson();
	cout << "T的数据类型:" << typeid(T).name() << endl;
}

void test03()
{
	Person<string, int>p("Lily", 20);
	printPerson3(p);
}

int main()
{
	test03();
	system("pause");
	return 0;
}

 总结:指定传入类型比较常用!

5)类模板与继承

  • 当子类继承的是父类木板时,子类声明的时候,需要指定父类模板中T的类型
  • 如果不指定,编译器无法给子类分配内存
  • 如果想灵活指定父类中T的类型,子类也需要变为模板
#include<iostream>
#include<string>
using namespace std;

//类模板的成员函数的类外实现

template<class T1,class T2>
class Person
{
public:
	Person(T1 name, T2 age);

	void showPerson();
	
	T1 m_Name;
	T2 m_Age;
};

//构造函数的类外实现
template<class T1,class T2>
Person<T1,T2>::Person(T1 name, T2 age)
{
	this->m_Name = name;
	this->m_Age = age;
}

//成员函数的类外实现
template<class T1,class T2>
void Person<T1,T2>::showPerson()//!!!必须写模板参数列表!!!
{
	cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl;
}

void test01()
{
	Person<string, int>p("Tom", 100);
	p.showPerson();
}

int main()
{
	test01();
	system("pause");
	return 0;
}

注意:成员函数的类外实现
template<class T1,class T2>
void Person<T1,T2>::showPerson()//!!!必须写模板参数列表!!! 

6)类模板分文件编写

类模板中的成员函数创建时机时在调用阶段,导致分文件编写时链接不上

  • 解决方法1:直接包含.cpp文件
  • 解决方法2:将声明和实现写到同一个文件中,并改后缀名为.hpp,hpp是约定的名称,并不强制

person1.hpp文件

#pragma once
#include<iostream>
using namespace std;

template<class T1, class T2>
class Person
{
public:
	Person(T1 name, T2 age);

	void showPerson();

	T1 m_Name;
	T2 m_Age;
};

template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
	this->m_Name = name;
	this->m_Age = age;
}

template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
	cout << "姓名:" << this->m_Name << "  年龄:" << this->m_Age << endl;
}

13模板-类模板分文件编写.cpp

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

//第一种解决方式
#include"person.cpp"//#include"person.h"改为#include"person.cpp"才不会报错

//第二种解决方式  将.h和.cpp文件中的内容写到一起,将后缀名改为.hpp文件
#include"person1.hpp"

//类模板的份文件编写
//类模板中的成员函数创建时机在调用阶段,导致分文件时链接不是
//
//template<class T1, class T2>
//class Person
//{
//public:
//	Person(T1 name, T2 age);
//
//	void showPerson();
//
//	T1 m_Name;
//	T2 m_Age;
//};

//template<class T1,class T2>
//Person<T1, T2>::Person(T1 name,T2 age)
//{
//	this->m_Name = name;
//	this->m_Age = age;
//}
//
//template<class T1, class T2>
//void Person<T1,T2>::showPerson()
//{
//	cout << "姓名:" << this->m_Name << "  年龄:" << this->m_Age << endl;
//}

void test01()
{
	Person<string, int>p("Susan", 19);
	p.showPerson();
}

int main()
{
	test01();
	system("pause");
	return 0;
}

7)类模板和友元:建议使用全局函数的类内实现

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

//类模板和友元
// 通过全局函数打印Person的信息

//提前让编译器知道Person类的存在
template<class T1,class T2>
class Person;

//全局函数  类外实现
template<class T1, class T2>
void printPerson2(Person<T1, T2> p)
{
	cout << "类外实现——Name: " << p.m_Name << "  Age:" << p.m_Age << endl;
}

template<class T1,class T2>
class Person
{
	//全局函数  类内实现
	friend void printPerson(Person<T1, T2> p)
	{
		cout << "Name: " << p.m_Name << "  Age:" << p.m_Age << endl;
	}

	//全局函数  类外实现
	//加空模板的参数列表
	//如果成员函数类外实现,需要让编译器提前知道这个函数的存在
	friend void printPerson2<>(Person<T1, T2> p);
public:
	Person(T1 name,T2 age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
private:
	T1 m_Name;
	T2 m_Age;
};


//类内实现测试
void test01()
{
	Person<string, int>p("Tom",10);
	printPerson(p);
}

//类外实现测试
void test02()
{
	Person<string, int>p("Susan", 2);
	printPerson2(p);
}

int main()
{
	//test01();
	test02();
	system(+"pause");
	return 0;
}

8)案例:通用的数组类

  • 运用知识:类模板、深浅拷贝、函数重载
  • c++学习笔记-提高编程-模板(哔站-黑马程序员c++教学视频)
  • 几个重点:

T* = new T[5];//new出来地址所以用地址变量承接,new的类型是T,所以指针数据类型也是T

”拷贝构造和operator=“防止在堆区数据浅拷贝带来的问题

T& operator[](int index)//函数调用作为左值,要反回引用&

  • 代码实现:

c++学习笔记-提高编程-模板(哔站-黑马程序员c++教学视频)文章来源地址https://www.toymoban.com/news/detail-410107.html

#pragma once
//自己通用的数组类
#include<iostream>
using namespace std;

template<class T>
class MyArray
{
public:
	//有参构造  参数 容量
	MyArray(int capacity)
	{
		//cout << "MyArray 的有参构造调用" << endl;
		this->m_Capacity = capacity;
		this->m_Size = 0;
		this->pAddress = new T[capacity];
	}

	MyArray(const MyArray& arr)//拷贝构造 防止浅拷贝问题
	{
		//cout << "MyArray 的拷贝构造调用" << endl;
		this->m_Capacity = arr.m_Capacity;
		this->m_Size = arr.m_Size;
		//this->pAddress = arr.pAddress;//浅拷贝导致堆区开辟空间重复释放

		//深拷贝
		this->pAddress = new T[arr.m_Capacity];
		//将arr中的数据拷贝过来了
		for (int i = 0; i < this->m_Size; i++)
		{
			this->pAddress[i] = arr.pAddress[i];
		}
	}

	//operater= 防止浅拷贝问题
	MyArray& operator=(const MyArray& arr)
	{
	    //cout << "MyArray 的operater=调用" << endl;
		//先判断原来堆区是否有数据,有就先释放
		if (this->pAddress != NULL)
		{
			delete[] this->pAddress;
			this->pAddress = NULL;
			this->m_Size = 0;
			this->m_Capacity = 0;
		}
		//深拷贝
		this->m_Capacity = arr.m_Capacity;
		this->m_Size = arr.m_Size;
		this->pAddress = new T[arr.m_Capacity];
		for (int i = 0; i < arr.m_Capacity; i++)
		{
			this->pAddress[i] = arr.pAddress[i];
		}
		return* this;
	}

	//尾增
	void Push_Back(const T& val)
	{
		//判断容量是否等于大小
		if (this->m_Capacity == this->m_Size)
		{
			return;
		}
		this->pAddress[this->m_Size] = val;//数组末尾插入数据
		this->m_Size++;//更新数组大小
	}

	//尾删
	void Pop_Back()
	{
		//让用户访问不到最后一个元素,即为尾删,逻辑删除
		if (this->m_Size == 0)
		{
			return;
		}
		this->m_Size--;
	}

	//用户通过下标访问数组中元素 arr[0]=100;
	T& operator[](int index)//函数调用作为左值,要反回引用&
	{
		return this->pAddress[index];
	}

	//返回数组容量
	int getCapacity()
	{
		return this->m_Capacity;
	}
	//返回数组大小
	int getSize()
	{
		return this->m_Size;
	}


	//析构函数 堆区数据清空
	~MyArray()
	{
		//cout << "MyArray 的析构函数调用" << endl;
		if (this->pAddress != NULL)
		{
			delete[] this->pAddress;
			this->pAddress = NULL;//指针置为空
		}
	}
private:
	T* pAddress;//指针指向堆区开辟的真实数组

	int m_Capacity;//数组容量

	int m_Size;
};

到了这里,关于c++学习笔记-提高编程-模板(哔站-黑马程序员c++教学视频)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot-黑马程序员-学习笔记(三)

    目录 30.springboot整合MyBatis-plus 32.SSM整合 38.MP中的条件查询 小知识:许多放在类前面的注解,比如@Mapper,@Service都是将该类定义成一个Bean,交给spring管理 39.Service模块 1.创建普通springboot项目,勾选Mysql 框架 2.在pom包里面导入mybatis-plus的坐标 3.把数据层的类继承BaseMapper这个接口

    2024年02月07日
    浏览(48)
  • 学习笔记-微服务高级(黑马程序员)

    测试软件 jmeter 雪崩问题 个微服务往往依赖于多个其它微服务,服务提供者I发生了故障,依赖于当前服务的其它服务随着时间的推移形成级联失败 超时处理 设定超时时间,请求超过一定时间没有响应就返回错误信息 仓壁模式 限定每个业务能使用的线程数,避免耗尽整个tom

    2024年04月25日
    浏览(54)
  • [学习笔记]黑马程序员python教程

    1.9.1异常的捕获 1.9.1.1 为什么要捕获异常 1.9.1.2 捕获常规的异常 1.9.1.3 捕获指定的异常 e是接受异常信息的变量 1.9.1.4 捕获多个异常 1.9.1.5 捕获全部异常 1.9.1.6 异常的else 1.9.1.7 异常的finally 1.9.2 异常的传递 如果异常是在某一层产生,但是没有被catch,那么会继续往上层抛出,此

    2024年02月07日
    浏览(69)
  • Linux命令基础,黑马程序员学习笔记

    command [-options] [parameter] command:命令本身 -options:[可选,非必填]命令的一些选项,可以通过选项控制命令的行为细节 parameter:[可选,非必填]命令的参数,多数用于命令的指向目标等 示例: ls -l /home/itheima ls是命令本身,-l是选项, /home/itheima是参数意思是以列表的形式,显示/home

    2024年02月19日
    浏览(97)
  • C++提高编程——模板

    本阶段主要针对C++ 泛型编程 和 STT 技术 做详细讲解,探讨C++更深层的使用 模板就是建立通用的模具,大大提高复用性 例如生活中的模板 寸照片模板: C++另一种编程思想称为 泛型编程 ,主要利用的技术就是模板 C++提供两种模板机制:函数模板和类模板 1.2.1函数模板语法 函

    2024年02月12日
    浏览(44)
  • [学习笔记]黑马程序员-Hadoop入门视频教程

    黑马程序员大数据Hadoop入门视频教程,适合零基础自学的大数据Hadoop教程 学习目标 1.理解大数据基本概念 2.掌握数据分析基本步骤 3.理解分布式、集群概念 4.学会VMware虚拟机的导入与使用 5.掌握Linux常用操作命令使用 6.掌握vi/vim编辑器基础使用 1.1.1 企业数据分析方向 数据分

    2024年02月13日
    浏览(54)
  • 【学习笔记】黑马程序员Java课程学习笔记(更新至第12章---集合)

    Java语言是美国Sun公司(Stanford University Network)在1995年推出的计算机语言, 2009年Oracle甲骨文公司收购Sun公司。Java之父:詹姆斯·高斯林(James Gosling)。 Java可以在任意操作系统上运行,Windows、Mac、Linux。我们只需要在运行Java应用程序的操作系统上,安装一个与操作系统对应

    2024年02月07日
    浏览(47)
  • 黑马程序员 Java设计模式学习笔记(一)

    目录 一、设计模式概述 1.1、23种设计模式有哪些? 1.2、软件设计模式的概念 1.3、学习设计模式的必要性 1.4、设计模式分类 二、UML图 2.1、类图概述 2.2、类图的作用 2.3、类图表示法 类的表示方式 类与类之间关系的表示方式 关联关系 聚合关系 组合关系 依赖关系 继承关系

    2024年01月19日
    浏览(52)
  • 黑马程序员--分布式搜索ElasticSearch学习笔记

    黑马视频地址:https://www.bilibili.com/video/BV1LQ4y127n4/ 想获得最佳的阅读体验,请移步至我的个人博客 SpringCloud学习笔记 消息队列MQ学习笔记 Docker学习笔记 分布式搜索ElasticSearch学习笔记 ElasticSearch的作用 ElasticSearch 是一款非常强大的开源搜素引擎,具备非常强大的功能,可以帮

    2024年02月04日
    浏览(47)
  • 黑马程序员Docker快速入门到项目部署(学习笔记)

    目录 一、Docker简介 二、安装Docker 2.1、卸载旧版 2.2、配置Docker的yum库 2.3、安装Docker 2.4、启动和校验 2.5、配置镜像加速 2.5.1、注册阿里云账号 2.5.2、开通镜像服务 2.5.3、配置镜像加速 三、快速入门 3.1、部署MYSQL 3.2、命令解读 四、Docker基础 4.1、常见命令 4.1.1、命令介绍 4.1

    2024年01月25日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包