C++的进阶泛型编程学习(2):类模板的机制

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、类模板
  • 二、类模板和函数模板的区别
    • 1.类模板没有自动类型推导的方式
    • 2.类模板在模板参数列表中可以有默认参数
  • 三、类模板对象做函数参数
  • 四、类模板与继承
    • 4.1当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
    • 4.2 如果不指定,编译器无法给子类分配内存
    • 4.3 如果想灵活指定出父类中T的类型,子类也需为类模板
  • 五、类模板成员函数类外实现
  • 六、类模板分文件编写
  • 八、类模板与友元
  • 九、类模板案例


前言

上一节学到函数模板,意思就是把函数的返回类型和传递参数类型用一个抽象的模板名来代替,从而起到支持泛化数据输入的功能,提高了函数的多用性。

那么类,可以使用模板机制来提高泛用性吗?当然可以。

一、类模板

类模板(Class Template)是C++中的一种特殊的模板,用于定义通用的类。类模板可以根据不同的数据类型生成具体的类,从而实现代码的复用和泛化。

类模板的定义同样使用关键字template,后面跟着模板参数列表,其中可以包含类型参数、非类型参数和模板参数的默认值。例如:

#include <iostream>
#include<string>using namespace std;template <class nametype, class agetype>
class person {// 类定义
public:person(nametype name, agetype age) {this->age = age;this->name = name;}nametype name;agetype age;
};int main(void) {person<string,int> p("李明", 15);person<string, float> p2("小红", 18.5);system("pause");return 0;
}

代码使用了类模板来定义了一个名为person的类,该类有两个模板参数:nametype和agetype,分别表示姓名和年龄的数据类型。

在person类中,有一个构造函数,接受两个参数:name和age,并将它们分别赋值给类的成员变量name和age。

在main函数中,你使用了类模板来实例化了两个不同类型的person对象。p是一个person<string, int>对象,name的类型为string,age的类型为int。p2是一个person<string, float>对象,name的类型为string,age的类型为float。

最后,你使用了system(“pause”)来暂停程序的执行,以便在Windows系统下查看输出结果。

二、类模板和函数模板的区别

1.类模板没有自动类型推导的方式

即:

person<string,int> p("李明", 15);//合法的

类模板实例化时必须指定参数类型

person p3("王刚", 14);//不合法的

不指定的话是不合法的。

2.类模板在模板参数列表中可以有默认参数

代码如下(示例):

#include <iostream>
#include<string>using namespace std;template <typename nametype, typename agetype=int>
class person {// 类定义
public:person(nametype name, agetype age) {this->age = age;this->name = name;}nametype name;agetype age;
};int main(void) {person<string,int> p("李明", 15);person<string, float> p2("小红", 18.5);person<string> p3("王刚", 14);system("pause");return 0;
}

提前指定好类模板参数列表的int型,那么实例化时就不用指定整形了。

三、类模板对象做函数参数

学习目标:类模板实例化出的对象,向函数传参的方式

一共有三种传入方式:

指定传入的类型:直接显示对象的数据类型
参数模板化:将对象中的参数变为模板进行传递
整个类模板化:将这个对象类型模板化进行传递

//类模板对象做函数参数
template<class T1,class T2>
class Person
{
public:Person(T1 name,T2 age){this->m_Age = age;this->m_Name = name;}void showPerson(){cout << "name: " << this->m_Name << " age:" << this->m_Age << endl;}T1 m_Name;T2 m_Age;
};//1、指定传入类型
void printPerson1(Person<string, int>&p)
{p.showPerson();
}
void test01()
{Person<string, int>p("孙悟空", 199);printPerson1(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("猪八戒", 90);printPerson2(p);
}// 3、整个类模板化
template<class T>
void printPerson3(T &p)
{p.showPerson();cout << "T的类型为:" << typeid(T).name() << endl;
}
void test03()
{Person<string, int>p("唐僧", 60);printPerson3(p);
}int main()
{test01();test02();test03();system("pause");return 0;
}

三种不同的方式来将类模板对象作为函数参数传递。

指定传入类型: 在printPerson1函数中,我们明确指定了Person<string, int>作为参数类型。然后我们创建一个Person<string, int>对象p,并将其传递给printPerson1函数。函数内部可以通过对象p调用成员函数showPerson来显示对象的信息。

参数模板化: 在printPerson2函数中,我们使用了参数模板化的方式,即Person<T1, T2>作为参数类型。然后我们创建一个Person<string, int>对象p,并将其传递给printPerson2函数。函数内部可以通过对象p调用成员函数showPerson来显示对象的信息。此外,我们还使用typeid来获取T1和T2的类型信息。

整个类模板化: 在printPerson3函数中,我们将整个类模板Person作为参数类型。然后我们创建一个Person<string, int>对象p,并将其传递给printPerson3函数。函数内部可以通过对象p调用成员函数showPerson来显示对象的信息。此外,我们还使用typeid来获取T的类型信息。

四、类模板与继承

当类模板碰到继承时,需要注意以下几点:

4.1当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型

//类模板与继承
template<class T>
class Base
{T m;
};//class Son: public Base //错误,必须要知道父类中的T类型,才能继承给子类
class Son :public Base<int>//合法
{};

4.2 如果不指定,编译器无法给子类分配内存

4.3 如果想灵活指定出父类中T的类型,子类也需为类模板

//如果想灵活指定父类中T的类型,子类也需要变成类模板
template<class T1,class T2>
class Son2 : public Base<T2>
{
public:Son2(){cout << "T1的类型为:" << typeid(T1).name() << endl;cout << "T2的类型为:" << typeid(T2).name() << endl;}T1 obj;
};

五、类模板成员函数类外实现

示例:

//类模板成员类外实现
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;
};//构造函数的类外实现
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", 30);p.showPerson();
}int main()
{test01();system("pause");return 0;
}

六、类模板分文件编写

如果工程中需要利用多个类模板,那么将这些类模板都写在同一个文件中将会导致代码可读性变差,所以有必要对类模板进行分文件编写,但是类模板的分文件编写面临着一些问题,以下是类模板分文件编写面临的问题及解决方法。

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

解决:

解决方式1:直接包含.cpp源文件
解决方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制的
示例1:(未进行分文件编写)

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;
};//构造函数的类外实现
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", 30);p.showPerson();
}int main()
{test01();system("pause");return 0;
}

实例2:(进行分文件编写,利用.cpp)

1.创建头文件person.h,写一些声明

#pragma once
#include <iostream>
using namespace std;
#include <string>template<class T1, class T2>
class Person
{
public:Person(T1 name, T2 age);void showPerson();T1 m_Name;T2 m_Age;
};

2.创建person.cpp,写具体实现

#include "person.h"//构造函数的类外实现
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;
}

3.main函数编写
错误代码:

#include <iostream>
using namespace std;
#include <string>
#include "person.h"void test01()
{Person<string, int>p("Tom", 30);p.showPerson();
}int main()
{test01();system("pause");return 0;
}

注:因为如果包含person.h文件,那么编译器将会看到person.h中的代码。但是由于类模板中的成员函数一开始是不创建的,导致编译器没有看到person.cpp中的代码,所以执行test01时,无法解析其中的代码。

正确代码:(不常用)

#include <iostream>
using namespace std;
#include <string>
#include "person.cpp"void test01()
{Person<string, int>p("Tom", 30);p.showPerson();
}int main()
{test01();system("pause");return 0;
}

注:就是将person.h文件改成了person.cpp代码。编译器首先看到了person.cpp文件,因为person.cpp文件中有person.h文件,编译器又看到了person.h文件,所以能够解析test01中的代码。但是一般很少直接包含.cpp文件的,所以这个方法不常用。

实例3:(分文件编写,利用.hpp)
将person.h和person.cpp的内容写到一起,并将后缀名改为.hpp,这是类模板分文件编写最常用的方式

1.编写person.hpp文件:

#pragma once
#include <iostream>
using namespace std;
#include <string>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;
}

2.编写main函数

#include <iostream>
using namespace std;
#include <string>
#include "person.hpp"void test01()
{Person<string, int>p("Tom", 30);p.showPerson();
}int main()
{test01();system("pause");return 0;
}

八、类模板与友元

全局函数类内实现:直接在类内声明友元即可
全局函数类外实现:需要提前让编译器知道全局函数的存在

1.全局函数的类内实现

template<class T1, class T2>
class Person
{//全局函数类内实现friend void printPerson(Person<T1, T2> p){cout << "姓名:" << p.m_Name << " 年龄:" << p.m_Age << endl;}
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", 30);printPerson(p);
}
int main()
{test01();system("pause");return 0;
}

2.全局函数类外实现

//提前让编译器知道Person类的存在
template<class T1, class T2>
class Person;//类外实现
template<class T1, class T2>
void printPerson(Person<T1, T2> p)
{cout << "姓名:" << p.m_Name << " 年龄:" << p.m_Age << endl;
}template<class T1, class T2>
class Person
{//全局函数类外实现 //加空模板参数列表//如果全局函数是类外实现,需要让编译器提前知道这个函数的存在friend void printPerson<>(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", 30);printPerson(p);
}int main()
{test01();system("pause");return 0;
}

注:需要注意各个函数声明之间的顺序。在Person类模板中有友元的声明friend void printPerson<>(Person<T1, T2> p),因为类模板中友元的类外实现需要让编译器提前知道这个函数,所以需要将printPerson函数写在前面。而printPerson函数中又涉及Person类,所以在printPerson函数前面需要提前声明Person类模板的存在。
总结:建议全局函数做类内实现,用法简单,而且编译器可以直接识别。

九、类模板案例

案例描述:

可以对内置数据类型以及自定义数据类型的数据进行存储
将数组中的数据存储到堆区
构造函数中可以传入数组的容量
提供对应的拷贝构造函数以及operator=防止浅拷贝的问题
提供尾插法和尾删法对数组中的数据进行增加和删除
可以通过下标的方式访问数组中的元素
可以获取数组中当前元素个数和数组的容量
MyArray.hpp文件:

#pragma once
#include <iostream>
using namespace std;template<class T>
class MyArray
{
public://构造函数MyArray(int capacity){cout << "MyArray有参构造的调用" << endl;this->m_Capacity = capacity;this->pAdress = new T[this->m_Capacity];this->m_Size = 0;}//析构函数~MyArray(){if (this->pAdress != NULL){cout << "MyArray析构的调用" << endl;delete[] this->pAdress;this->pAdress = NULL;}}//拷贝构造MyArray(const MyArray& arr){cout << "MyArray拷贝构造的调用" << endl;this->m_Capacity = arr.m_Capacity;this->m_Size = arr.m_Size;//深拷贝this->pAdress = new T[arr.m_Capacity];//将arr中的数据都拷贝过来for (int i = 0; i < this->m_Size; i++){this->pAdress[i] = arr.pAdress[i];}}//operator= 防止浅拷贝问题MyArray& operator=(const MyArray& arr){cout << "MyArray的operator=调用" << endl;//先判断原来堆区是否有数据,如果有先释放if (this->pAdress != NULL){delete[] this->pAdress;this->pAdress = NULL;this->m_Capacity = 0;this->m_Size = 0; }this->m_Capacity = arr.m_Capacity;this->m_Size = arr.m_Size;//深拷贝this->pAdress = new T[arr.m_Capacity];//将arr中的数据都拷贝过来for (int i = 0; i < this->m_Size; i++){this->pAdress[i] = arr.pAdress[i];}return *this;}//尾插法void Push_Back(const T& val){//判断容量是否等于大小if (this->m_Size == this->m_Capacity){return;}this->pAdress[this->m_Size] = val; //在数组末尾插入数据this->m_Size++; //更新数组大小}//尾删法void Pop_Back(){//让用户访问不到最后一个元素即为尾删法 if (this->m_Size == 0){return;}this->m_Size--;}//通过下标方式访问数组中的元素T& operator[](int index) //以引用作为返回值是为了能够做arr[0]=100这样的操作{return this->pAdress[index];}//返回数组容量int getCapacity(){return this->m_Capacity;}//返回数组大小int getSize(){return this->m_Size;}private:T *pAdress; //指针指向堆区开辟的真实数组int m_Capacity; //数组容量int m_Size; //数组大小
};

main文件:

#include <iostream>
using namespace std;
#include "MyArray.hpp"
#include <string>void printIntArray(MyArray<int>& arr1)
{for (int i = 0; i < arr1.getSize(); i++){cout << arr1[i] << " ";}cout << endl;
}void test01()
{MyArray<int> arr1(5);MyArray<int> arr2(arr1);MyArray<int> arr3(100);arr3 = arr1;cout << "--------------------" << endl;MyArray<int>arr4(5);for (int i = 0; i < 5; i++){//通过尾插法向数组中插入数据arr4.Push_Back(i);}cout << "arr4的打印输出为:" << endl;printIntArray(arr4);cout << "arr4的容量为:" << arr4.getCapacity() << endl;cout << "arr4的大小为:" << arr4.getSize() << endl;MyArray<int>arr5(arr4);cout << "arr5的打印输出为:" << endl;printIntArray(arr5);//尾删法arr5.Pop_Back();cout << "arr5尾删后的打印输出为:" << endl;printIntArray(arr5);
}//测试自定义类型
class Person
{
public:Person(){}Person(string name,int age){this->m_Age = age;this->m_Name = name;}string m_Name;int m_Age;
};void printPersonArray(MyArray<Person>& arr)
{for (int i = 0; i < arr.getSize(); i++){cout << "Name: " << arr[i].m_Name << "  Age: " << arr[i].m_Age << endl;}
}void test02()
{MyArray<Person> arr(10);Person p1("Tom", 12);Person p2("Jack", 15);Person p3("Bill", 17);//数据插入到数组中arr.Push_Back(p1);arr.Push_Back(p2);arr.Push_Back(p3);printPersonArray(arr);cout << "arr的容量为:" << arr.getCapacity() << endl;cout << "arr的大小为:" << arr.getSize() << endl;
}int main()
{test01();cout << "==========" << endl;test02();system("pause");return 0;
}

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

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

相关文章

【Deep Learning 2】神经网络的优化

&#x1f31e;欢迎来到PyTorch的世界 &#x1f308;博客主页&#xff1a;卿云阁 &#x1f48c;欢迎关注&#x1f389;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f31f;本文由卿云阁原创&#xff01; &#x1f4c6;首发时间&#xff1a;&#x1f339;2024年2月16日&a…

平滑几何名词

G0: Position (touching) G1: Tangent (angle) G2: Curvature (radius) G3&#xff1a; A G3 path is characterized by a continuously differentiable curvature profile。Acceleration/Torsion (rate of change of curvature 、 sharpness) clothoid: An Euler spi…

2.16C语言学习

P1296 奶牛的耳语 一开始以为是普通的二重循环&#xff0c;结果做出来答案是错的&#xff0c;但是思路不可能有问题&#xff0c;于是抱着试一试的想法加了一个排序&#xff0c;这样就过了&#xff0c;每次在第二重循环里遇到大于最小能听到的距离就跳出循环&#xff0c;进入下…

java8-重构、测试、调试

8.1.1 改善代码的可读性 改善代码的可读性到底意味着什么?我们很难定义什么是好的可读性&#xff0c;因为这可能非常主观。通常的理解是&#xff0c;“别人理解这段代码的难易程度”。改善可读性意味着你要确保你的代码能非常容易地被包括自己在内的所有人理解和维护。为了确保…

在Spring中事务失效的场景

在Spring框架中&#xff0c;事务管理是通过AOP&#xff08;面向切面编程&#xff09;实现的&#xff0c;主要依赖于Transactional注解。然而&#xff0c;在某些情况下&#xff0c;事务可能会失效。以下是一些可能导致Spring事务失效的常见场景&#xff1a; 非public方法&#…

2月16日,每日信息差

第一、2024春节档总观影人次进入影史前二&#xff0c;截至2月16日16时31分&#xff0c;2024年春节档总观影人次达1.46亿&#xff08;含预售&#xff09;&#xff0c;超2018年春节档总观影人次1.45亿&#xff0c;成为中国影史春节档总观影人次第二名。《热辣滚烫》《飞驰人生2》…

阿里云“BGP(多线)”和“BGP(多线)_精品”区别价格对比

阿里云香港等地域服务器的网络线路类型可以选择BGP&#xff08;多线&#xff09;和 BGP&#xff08;多线&#xff09;精品&#xff0c;普通的BGP多线和精品有什么区别&#xff1f;BGP&#xff08;多线&#xff09;适用于香港本地、香港和海外之间的互联网访问。使用BGP&#xf…

悦纳自己:拥抱个人局限,开启成长之旅

悦纳自己&#xff1a;拥抱个人局限&#xff0c;开启成长之旅 在人生的旅途中&#xff0c;我们每个人都会面临无数的挑战和选择。有时我们会因为这些挑战而感到焦虑和不安&#xff0c;因为我们害怕失败&#xff0c;害怕无法达到预期的目标。然而&#xff0c;真正重要的是我们如何…

Selenium实战教程系列(三)--- Selenium中的动作

Selenium中针对元素进行的动作在代码中可以分为两类&#xff1a; Selenium::WebDriver::ActionBuilder类中的动作方法Selenium::WebDriver::Element类中的动作方法 其中ActionBuilder类中的动作方法比较丰富&#xff0c;基本涵盖了所有可以进行的操作。 而Element类的动作比较…

12.16 校招 实习 内推 面经

绿*泡*泡VX&#xff1a; neituijunsir 交流裙 &#xff0c;内推/实习/校招汇总表格 1、校招 | 2024届比亚迪博士招聘 校招 | 2024届比亚迪博士招聘 2、校招 | 长光卫星2024校招热门岗位补招中 校招 | 长光卫星2024校招热门岗位补招中 3、校招 | 云道智造2024全球校园招聘 …

Linux目录结构

Linux常用目录结构 /&#xff1a;根目录存放在系统的所有文件 ~&#xff1a;一般特指当前用户的家目录。root用户一般为&#xff1a;/root&#xff0c;普通用户为&#xff1a;/home/用户名 /home&#xff1a;新用户新建时&#xff0c;会在此目录建立新的用户文件&#xff0c;…

C#系列-​​​​​​​EntityFrameworkCore.Transactions.Abstractions应用场景+实例(38)

EntityFrameworkCore.Transactions.Abstractions应用场景 EntityFrameworkCore.Transactions.Abstractions 并不是一个官方的或广泛认可的 NuGet 包名称。在 Entity Framework Core (EF Core) 中&#xff0c;事务管理通常是通过 DbContext 的内置方法来实现的&#xff0c;如 Sa…

xtu oj 1146 矩阵乘法

题目描述 给你两个矩阵A(n*k),B(k*m),请求A*B。 输入 第一行是一个整数K&#xff0c;表示样例的个数。 每个样例包含两个矩阵A和B。 每个矩阵的第一行是两个整数n,m,(1≤n,m≤10)表示矩阵的行和列 以后的n行&#xff0c;每行m个整数&#xff0c;每个整数的绝对值不超过100。…

C#根据权重抽取随机数

&#xff08;游戏中一个很常见的简单功能&#xff0c;比如抽卡抽奖抽道具&#xff0c;或者一个怪物有多种攻击动作&#xff0c;按不同的权重随机出个攻击动作等等……&#xff09; 假如有三种物品 A、B、C&#xff0c;对应的权重分别是A&#xff08;50&#xff09;&#xff0c…

积分(二)——复化Simpson(C++)

前言 前言 simpson积分 simpson积分公式 ∫ a b f ( x ) d x ≈ b − a 6 [ f ( a ) f ( b ) 4 f ( a b 2 ) ] \int_{a}^{b}f(x)dx \approx \frac{b-a}{6}[f(a)f(b)4f(\frac{ab}{2})] ∫ab​f(x)dx≈6b−a​[f(a)f(b)4f(2ab​)] 与梯形积分类似&#xff0c;当区间[a,b]较…

浅析Linux追踪技术之ftrace:综述

文章目录 概述Ftrace工作原理Ftrace追踪器Ftrace探测技术GCC的profile特性 tracefs文件系统控制文件trace信息 Ftrace使用tracer配置步骤function tracer使用示例 相关参考 概述 Ftrace&#xff0c;全称Function Tracer&#xff0c;是一个内部跟踪器&#xff0c;旨在帮助系统的…

关于项目中websocket的socket.io客户端js库的应用

1.如何使用客户端js库? pnpm add socket.io-client2.如何建立连接&#xff1f; import io from socket.io-client // 参数1&#xff1a;不传默认是当前服务域名&#xff0c;开发中传入服务器地址 // 参数2&#xff1a;配置参数&#xff0c;根据需要再来介绍 const socket i…

JavaScript中null和undefined的区别

JavaScript中null和undefined是两个特殊的值&#xff0c;经常在编程中遇到。虽然它们经常被混淆&#xff0c;但它们有着不同的含义和用法。本文将详细介绍JavaScript中null和undefined的区别&#xff0c;帮助开发者更好地理解和使用它们。 首先&#xff0c;让我们来了解一下nu…

EF Core 模型优先——根据类对象创建数据表

需要的nuget包&#xff1a; Microsoft.EntityframeworkCore.SqlServer &#xff08;根据自己的数据库类型选择对应的nuget包&#xff09; Microsoft.EntityframeworkCore.Tools Microsoft.VisualStudio.Web.CodeGeneration.Design 说明&#xff1a; &#xff08;1&#xf…

[java基础揉碎]数组 值拷贝和引用拷贝的赋值方式

目录 数组的介绍 为什么有数组 数组的三种使用方式 动态初始化: 静态初始化: 数组使用注意事项和细节 值拷贝和引用拷贝的赋值方式 数组反转: 数组拷贝: 数组的介绍 数组可以存放多个同一类型的数据。数组也是一种数据类型&#xff0c;是引用类型。 即&#xff1a;数组…