C++_04

1、继承

1.1 基本概念

        继承是面向对象编程(OOP)中的一个核心概念,特别是在C++中。它允许一个类(称为派生类或子类)继承另一个类(称为基类或父类)的属性和方法。继承的主要目的是实现代码重用,以及建立一种类型之间的层次关系。

        特点:

        (1)代码重用:子类继承了父类的属性和方法,减少了代码的重复编写。

        (2)扩展性:子类可以扩展父类的功能,添加新的属性和方法,或者重写(覆盖)现有的方法。

        (3)多态性:通过继承和虚函数,C++支持多态,允许在运行时决定调用哪个函数。

        在C++中,继承可以是公有(public)、保护(protected)或私有(private)的,这决定了基类成员在派生类中的访问权限。

#include <iostream>

using namespace std;

//基类,父类
class Vehicle{ //交通工具,车,抽象的概念
public:
    string type;
    string contry;
    string color;
    double price;
    int numOfWheel;

    void run(){
        cout << "车跑起来了" << endl;
    }
    void stop();
};

//派生类,子类
class Bickle : public Vehicle{

};

//派生类,子类
class Roadster : public Vehicle{ //跑车,也是抽象,比父类感觉上范围缩小了点
public:
    int stateOfTop;
    void openTopped();
    void pdrifting();
};

int main()
{
    Roadster ftype;
    ftype.type = "捷豹Ftype";
    ftype.run();
    Bickle bike;
    bike.type = "死飞";
    bike.run();

    return 0;
}

        在这个例子中, Vehicle 类公有地继承自 Vehicle 类,这意味着所有 Vehicle 类的公有成员在

Vehicle 类中也是公有的。

1.2 权限对继承的影响

        在C++中,访问控制符对继承的影响可以通过下表来清晰地展示。这个表格展示了不同类型的继承( public protected private )如何影响基类的不同类型成员( public protected 、private )在派生类中的访问级别。

基类成员类型
public 继承
protected 继承
private 继承
public
publicprotectedprivate
protected
protectedprotectedprivate
private
不可访问不可访问不可访问

        通过上表可知:

        (1)public 继承:基类的 public 成员在派生类中仍然是 public 的, protected 成员仍然是protected 的。基类的 private 成员在派生类中不可访问。

        (2)protected 继承:基类的 public protected 成员在派生类中都变成 protected 的。基类的 private 成员在派生类中不可访问。

        (3)private 继承:基类的 public protected 成员在派生类中都变成 private 的。基类的private 成员在派生类中不可访问。

        访问权限回顾

访问权限
类内部
同一个类的对象
派生类(子类)
类外部
public
✔️ 可访问
✔️ 可访问
✔️ 可访问
✔️ 可访问
private
✔️ 可访问
不可访问
不可访问
不可访问
protected
✔️ 可访问
不可访问
✔️ 可访问
不可访问

 1.3 基类构造函数

         在C++中,派生类可以通过其构造函数的初始化列表来调用基类的构造函数。这是在构造派生类对象时初始化基类部分的标准做法

        当创建派生类的对象时,基类的构造函数总是在派生类的构造函数之前被调用。如果没有明确指定,将调用基类的默认构造函数。如果基类没有默认构造函数,或者需要调用一个特定的基类构造函数,就需要在派生类构造函数的初始化列表中明确指定。 

class Base {
public:
    int data;

    Base(int x) {
        std::cout << "Base constructor with x = " << x << std::endl;
    }
};

class Derived : public Base {
public:
    double ydata;

    Derived(int x, double y) : Base(x) { // 调用 Base 类的构造函数
        std::cout << "Derived constructor with y = " << y << std::endl;
    }
};

int main() {
    Derived obj(10, 3.14); // 首先调用 Base(10),然后调用 Derived 的构造函数

    return 0;
}

        在上述例子中:Base 类有一个接受一个整数参数的构造函数。Derived 类继承自 Base ,它的构造函数接受一个整数和一个双精度浮点数。在其初始化列表中,它调用 Base 类的构造函数,并传递整数参数。当 Derived 类的对象被创建时,首先调用 Base 类的构造函数,然后调用 Derived 类的构造函数。

        通过这种方式,派生类能够确保其基类部分被正确初始化。在继承层次结构中,这是非常重要的,特别是当基类需要一些特定的初始化操作时。

#include <iostream>

using namespace std;

//基类,父类
class Vehicle{ //交通工具,车,抽象的概念
public:
    string contry;
    double price;

    Vehicle(string contry, double price){
        cout << "基类的构造函数被调用" << endl;
        this->contry = contry;
        this->price = price;
    };

    void run(){
        cout << "车跑起来了" << endl;
    }

    void stop();
};

//派生类,子类
class Roadster : public Vehicle{ //跑车,也是抽象,比父类感觉上范围缩小了点
public:
    int stateOfTop;

    Roadster(string contry, double price, int state) : Vehicle(contry, price){
        cout << "派生类的构造函数被调用" << endl;
        stateOfTop = state;
    }

    void openTopped();
    void pdrifting();
};

int main()
{
    Roadster FTYPE("法国",70,0);

    return 0;
}

1.4 虚函数

        在C++中, virtual override 关键字用于支持多态,尤其是在涉及类继承和方法重写的情况下。正确地理解和使用这两个关键字对于编写可维护和易于理解的面向对象代码至关重要。

1.4.1 virtual 关键字

        使用场景:在基类中声明虚函数。

        目的:允许派生类重写该函数,实现多态。

        行为:当通过基类的指针或引用调用一个虚函数时,调用的是对象实际类型的函数版本。

class Base {
public:
    virtual void func() {
        std::cout << "Function in Base" << std::endl;
    }
};

 1.4.2 override 关键字

        使用场景:在派生类中重写虚函数。

        目的:明确指示函数意图重写基类的虚函数。

        行为:确保派生类的函数确实重写了基类中的一个虚函数。如果没有匹配的虚函数,编译器会报错。

class Derived : public Base {
public:
    void func() override {
        std::cout << "Function in Derived" << std::endl;
    }
};

        注:(1)只在派生类中使用 overrideoverride 应仅用于派生类中重写基类的虚函数。

        (2)虚析构函数:如果类中有虚函数,通常应该将析构函数也声明为虚的。

        (3)默认情况下,成员函数不是虚的:在C++中,成员函数默认不是虚函数。只有显式地使用 virtual 关键字才会成为虚函数。

        (4)继承中的虚函数:一旦在基类中声明为虚函数,该函数在所有派生类中自动成为虚函数,无论是否使用 virtual 关键字。

1.5 多重继承

        在C++中,多重继承是一种允许一个类同时继承多个基类的特性。这意味着派生类可以继承多个基类的属性和方法。多重继承增加了语言的灵活性,但同时也引入了额外的复杂性,特别是当多个基类具有相同的成员时。

        在多重继承中,派生类继承了所有基类的特性。这包括成员变量和成员函数。如果不同的基类有相同名称的成员,则必须明确指出所引用的是哪个基类的成员。

        假设假设有两个基类 ClassA ClassB ,以及一个同时从这两个类继承的派生类 Derived

class ClassA {
public:
    void displayA() {
        std::cout << "Displaying ClassA" << std::endl;
    }
};

class ClassB {
public:
    void displayB() {
        std::cout << "Displaying ClassB" << std::endl;
    }
};

class Derived : public ClassA, public ClassB {
public:
    void display() {
        displayA(); // 调用 ClassA 的 displayA
        displayB(); // 调用 ClassB 的 displayB
    }
};

int main() {
    Derived obj;
    obj.displayA(); // 调用 ClassA 的 displayA
    obj.displayB(); // 调用 ClassB 的 displayB
    obj.display(); // 调用 Derived 的 display
    
    return 0;
}

        在这个示例中, Derived 类同时继承了 ClassA ClassB 。因此,它可以使用这两个类中定义的方法。

        注:(1)菱形继承问题:如果两个基类继承自同一个更高层的基类,这可能导致派生类中存在两份基类的副本,称为菱形继承(或钻石继承)问题。这可以通过虚继承来解决。

        (2)复杂性:多重继承可能会使类的结构变得复杂,尤其是当继承层次较深或类中有多个基类时。

        (3)设计考虑:虽然多重继承提供了很大的灵活性,但过度使用可能导致代码难以理解和维护。在一些情况下,使用组合或接口(纯虚类)可能是更好的设计选择。

        多重继承是C++的一个强大特性,但应谨慎使用。合理地应用多重继承可以使代码更加灵活和强大,但不当的使用可能导致设计上的问题和维护困难。

1.6 虚继承

        虚继承C++中一种特殊的继承方式,主要用来解决多重继承中的菱形继承问题。在菱形继承结构中,一个类继承自两个具有共同基类的类时,会导致共同基类的成员在派生类中存在两份拷贝,这不仅会导致资源浪费,还可能引起数据不一致的问题。虚继承通过确保共同基类的单一实例存在于继承层次中,来解决这一问题。

1.6.1 菱形继承

class Base {
public:
    int data;
};

class Derived1 : public Base {
    // 继承自 Base
};

class Derived2 : public Base {
    // 继承自 Base
};

class FinalDerived : public Derived1, public Derived2 {
    // 继承自 Derived1 和 Derived2
};

        在这个例子中, FinalDerived 类通过 Derived1 Derived2 间接地继承自 Base 类两次。因此,它包含了两份 Base 的成员拷贝。

1.6.2 使用虚继承解决菱形继承问题

class Base {
public:
    int data;
};

class Derived1 : virtual public Base {
    // 虚继承 Base
};

class Derived2 : virtual public Base {
    // 虚继承 Base
};

class FinalDerived : public Derived1, public Derived2 {
    // 继承自 Derived1 和 Derived2
};

        通过将 Derived1 Derived2 Base 的继承声明为虚继承( virtual public Base ),FinalDerived 类中只会有一份 Base 类的成员。无论通过 Derived1 还是 Derived2 的路径,访问的都是同一个 Base 类的成员。

        注:(1)初始化虚基类:在使用虚继承时,虚基类(如上例中的 Base 类)只能由最派生的类(如FinalDerived )初始化。

        (2)内存布局:虚继承可能会改变类的内存布局,通常会增加额外的开销,比如虚基类指针。

        (3)设计考虑:虚继承应谨慎使用,因为它增加了复杂性。在实际应用中,如果可以通过其他设计(如组合或接口)避免菱形继承,那通常是更好的选择。

1.7 小结

学习内容
描述
继承的基础
理解基类和派生类的概念,以及如何通过继承扩展类功能。了解不同继承类型(公有、私有、保护)及其影响。
构造函数和析构函数在继承中的行为
学习派生类如何调用基类的构造函数和析构函数,以及它们的调用顺序。
访问控制和继承
理解公有、私有和保护继承对成员访问权限的影响。掌握继承中的访问修饰符(public, protected, private )。
函数重写和多态
学习多态和如何通过虚函数实现它,了解如何重写基类方法,以及纯虚函数和抽象类的概念。
虚继承和解决菱形问题
理解菱形继承问题及其解决方式,学习如何使用虚继承。
C++11 新特性中的继承相关内容
理解和应用 override final 关键字,了解移动语义在继承中的应用。
设计原则与最佳实践
学习正确使用继承的方法,区分何时使用继承,何时使用组合,以及面向对象设计原则的应用。
实际案例分析
通过分析和编写实际代码示例加深理解,研究设计模式中继承的应用。

2、多态

        举个例子,假如你有一个遥控器(这就像是一个基类的指针),这个遥控器可以控制不同的电子设备(这些设备就像是派生类)。无论是电视、音响还是灯光,遥控器上的“/按钮(这个按钮就像是一个虚函数)都能控制它们,但具体的操作(打开电视、播放音乐、开灯)则取决于你指向的设备。

2.1 如何实现多态

        (1)使用虚函数(Virtual Function: 在基类中定义一个虚函数,这个函数可以在任何派生类中被“重写或者说定制。使用关键字 virtual 来声明。

        (2)创建派生类并重写虚函数:在派生类中,我们提供该虚函数的具体实现。这就像是告诉遥控器,“当你控制我的这个设备时,这个按钮应该这样工作”。

        (3)通过基类的引用或指针调用虚函数:当我们使用基类类型的指针或引用来调用虚函数时,实际调用的是对象的实际类型(派生类)中的函数版本。

#include <iostream>

using namespace std;

class RemoteCon{
public:
    virtual void openUtils(){
        cout << "遥控器的开被按下" << endl;
    }
};

class TvRemoteCon : public RemoteCon{
public:
    void openUtils() override{
        cout << "电视遥控器的开被按下" << endl;
    }
    void testFunc(){

    }
};

class RoundspeakerCon : public RemoteCon{
public:
    void openUtils() override{
        cout << "音响遥控器的开被按下" << endl;
    }
};

class LightCon : public RemoteCon{
public:
    void openUtils() override{
        cout << "灯光遥控器的开被按下" << endl;
    }
};

void test(RemoteCon& r)//引用的方式
{
    r.openUtils();
}

int main()
{
    RemoteCon *remoteCon = new TvRemoteCon; //多态
    remoteCon->openUtils();

    RemoteCon *remoteCon2 = new TvRemoteCon; //多态
    remoteCon2->openUtils();

    RemoteCon *remoteCon3 = new LightCon; //多态
    remoteCon3->openUtils();

    TvRemoteCon tvRemote;
    test(tvRemote);

    return 0;
}

2.2 抽象类

        在 C++ 中,抽象类就像是这样的一个抽象概念。它定义了一组方法(比如移动),但这些方法可能没有具体的实现。这意味着,抽象类定义了派生类应该具有的功能,但不完全实现这些功能。

        抽象类的特点:

        ( 1)包含至少一个纯虚函数:抽象类至少有一个纯虚函数。这是一种特殊的虚函数,在抽象类中没有具体实现,而是留给派生类去实现。纯虚函数的声明方式是在函数声明的末尾加上 = 0 。

        (2)不能直接实例化:由于抽象类不完整,所以不能直接创建它的对象。就像你不能直接使用“交通工具”的概念去任何地方,你需要一个具体的交通工具。

        (3)用于提供基础结构:抽象类的主 要目的是为派生类提供一个共同的基础结构,确保所有派生类都有一致的接口和行为。

#include <iostream>

using namespace std;

class Teacher{
public:
    string name;
    string shool;
    string major;
    virtual void goInClass() = 0;
    virtual void startTeaching() = 0;
    virtual void afterTeaching() = 0;
};

class EnglishTeacher : public Teacher{
public:
    void goInClass() override{
        cout << "英语老师开始进入教室" << endl;
    }

    void startTeaching() override{
        cout << "英语老师开始教学" << endl;
    }

    void afterTeaching() override{

    };
};

class ProTeacher : public Teacher{
public:
    void goInClass() override{
        cout << "编程老师开始进入教室" << endl;
    }

    void startTeaching() override{
        cout << "编程老师开始撸代码了,拒绝读PPT" << endl;
    }

    void afterTeaching() override{
        cout << "编程老师下课后手把手教x学员写代码" << endl;
    };
};

int main()
{
    // Teacher t;//抽象类,不支持被实例化
    EnglishTeacher e;
    e.goInClass();
    ProTeacher t;
    t.startTeaching();
    t.afterTeaching();

    //抽象类,多态
    Teacher *teacher = new ProTeacher;
    teacher->startTeaching();

    return 0;
}

2.3 纯虚函数-接口

        在 C++ 中,虽然没有像其他编程语言(比如 Java 中的接口Interface)一样直接定义接口的关键字,但可以通过抽象类和纯虚函数的方式来实现接口的概念。

        接口通常用于定义类应该实现的方法,但不提供具体实现。这样的实现方式允许多个类共享相同的接口,同时让每个类根据需要去实现这些接口。

        一个类作为接口可以通过以下步骤来实现:

        (1)定义抽象类:创建一个包含纯虚函数的抽象类,这些函数构成了接口的一部分。这些函数在抽象类中只有声明而没有具体的实现。

        (2)派生类实现接口:派生类继承抽象类,并实现其中的纯虚函数,以具体实现接口定义的方法。

#include <iostream>

using namespace std;

class BasketBallMove{
public:
    virtual void passTheBall() = 0;
};

class LiveMove{
public:
    virtual void eat() = 0;
    virtual void bite() = 0;
    virtual void drink() = 0;
    virtual void la() = 0;
};

class Human : public LiveMove,BasketBallMove{
public:
    void eat() override{};
    void bite() override{};
    void drink() override{};
    void la() override{};
    void passTheBall() override{};
};

class Dog : public LiveMove{
public:
    void eat() override{};
    void bite() override{};
    void drink() override{};
    void la() override{};
};

int main()
{
    Human h;
    Dog g;
    // LiveMove *l = new LiveMove;

    return 0;
}

        通过这种方式,可以在 C++ 中模拟出类似接口的行为,允许多个类共享相同的接口并提供各自的实现。

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

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

相关文章

打卡第2天----数组双指针,滑动窗口

今天是参与训练营第二天&#xff0c;这几道题我都看懂了&#xff0c;自己也能写出来了&#xff0c;实现思路很重要&#xff0c;万事开头难&#xff0c;希望我可以坚持下去。希望最后的结果是量变带来质变。 一、理解双指针思想 leetcode编号&#xff1a;977 不止是在卡尔这里…

深入探讨JavaScript中的队列,结合leetcode全面解读

前言 队列作为一种基本的数据结构&#xff0c;为解决许多实际问题提供了有效的组织和处理方式&#xff0c;对于提高系统的稳定性、可靠性和效率具有重要作用&#xff0c;所以理解队列是很重要的。 本文深入探讨JavaScript中的队列这种数据结构,结合leetcode题目讲解 题目直达…

接口测试工具Postman

Postman Postman介绍 开发API后&#xff0c;用于API测试的工具。在我们平时开发中&#xff0c;特别是需要与接口打交道时&#xff0c;无论是写接口还是用接口&#xff0c;拿到接口后肯定都得提前测试一下。在开发APP接口的过程中&#xff0c;一般接口写完之后&#xff0c;后端…

78110A雷达信号模拟软件

78110A雷达信号模拟软件 78110A雷达信号模拟软件(简称雷达信号模拟软件)主要用于模拟产生雷达发射信号和目标回波信号&#xff0c;软件将编译生成的雷达信号任意波数据下载到信号发生器中&#xff0c;主要是1466-V矢量信号发生器&#xff0c;可实现雷达信号模拟产生。软件可模…

TensorRT-Int8量化详解

int8量化是利用int8乘法替换float32乘法实现性能加速的一种方法 对于常规模型有&#xff1a;y kx b&#xff0c;此时x、k、b都是float32, 对于kx的计算使用float32的乘法 对于int8模型有&#xff1a;y tofp32(toint8(k) * toint8(x)) b&#xff0c;其中int8 * int8结果为in…

SpringBoot的热部署和日志体系

SpringBoot的热部署 每次修改完代码&#xff0c;想看效果的话&#xff0c;不用每次都重新启动代码&#xff0c;等待项目重启 这样就可以了 JDK官方提出的日志框架&#xff1a;Jul log4j的使用方式&#xff1a; &#xff08;1&#xff09;引入maven依赖 &#xff08;2&#x…

头歌资源库(20)最大最小数

一、 问题描述 二、算法思想 使用分治法&#xff0c;可以将数组递归地分割成两部分&#xff0c;直到数组长度为1或2。然后比较这两部分的最大、次大、次小、最小数&#xff0c;最终得到整个数组中的最大两个数和最小两个数。 算法步骤如下&#xff1a; 定义一个函数 findMinM…

uniapp/Android App上架三星市场需要下载所需要的SDK

只需添加以下一个权限在AndroidManifest.xml <uses-permission android:name"com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY"/>uniapp开发的&#xff0c;需要在App权限配置中加入以上的额外权限&#xff1a;

Generative Modeling by Estimating Gradients of the Data Distribution

Generative Modeling by Estimating Gradients of the Data Distribution 本文介绍宋飏提出的带噪声扰动的基于得分的生成模型。首先介绍基本的基于得分的生成模型的训练方法&#xff08;得分匹配&#xff09;和采样方法&#xff08;朗之万动力学&#xff09;。然后基于流形假…

2024 年 亚太赛 APMCM (B题)中文赛道国际大学生数学建模挑战赛 |洪水灾害数据分析 | 数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2022年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题&#xff01; 完整内容可以在文章末尾领取&#xff01; 该段文字…

HTML内容爬取:使用Objective-C进行网页数据提取

网页爬取简介 网页爬取&#xff0c;通常被称为网络爬虫或爬虫&#xff0c;是一种自动浏览网页并提取所需数据的技术。这些数据可以是文本、图片、链接或任何网页上的元素。爬虫通常遵循一定的规则&#xff0c;访问网页&#xff0c;解析页面内容&#xff0c;并存储所需信息。 …

自动化立体仓库出入库能力及堆垛机节拍

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》人俱乐部 完整版文件和更多学习资料&#xff0c;请球友到知识星球【智能仓储物流技术研习社】自行下载 自动化立体仓库的出入库能力、堆垛机节拍以…

用720云搭建数字孪生VR智慧安防系统,赋能安防升级!

“安全防范"一直是我国城镇化发展进程中重点关注的工作板块&#xff0c;随着时代发展需求与科技的日新月异&#xff0c;安防行业正在积极融合VR3D数字孪生技术&#xff0c;升级安防数字基础设施和安防产品服务创新。 今年2月&#xff0c;《数字中国建设整体布局规划》的出…

Pycharm的终端(Terminal)中切换到当前项目所在的虚拟环境

1.在Pycharm最下端点击终端/Terminal, 2.点击终端窗口最上端最右边的∨&#xff0c; 3.点击Command Prompt&#xff0c;切换环境&#xff0c; 可以看到现在环境已经由默认的PS(Window PowerShell)切换为项目所使用的虚拟环境。 4.更近一步&#xff0c;如果想让Pycharm默认显示…

macOS使用Karabiner-Elements解决罗技鼠标G304连击、单击变双击的故障

记录一下罗技鼠标G304单击变双击的软件解决过程和方案&#xff08;适用于macOS&#xff0c; 如果是Windows&#xff0c;使用AutoHotKey也有类似解决办法、方案&#xff0c;改日提供&#xff09;&#xff1a; 背景&#xff1a;通过罗技Logitech G HUB软件对罗技的游戏鼠标侧键b…

1-4 NLP发展历史与我的工作感悟

1-4 NLP发展历史与我的工作感悟 主目录点这里 第一个重要节点&#xff1a;word2vec词嵌入 能够将无限的词句表示为有限的词向量空间&#xff0c;而且运算比较快&#xff0c;使得文本与文本间的运算有了可能。 第二个重要节点&#xff1a;Transformer和bert 为预训练语言模型发…

2024 世界人工智能大会暨人工智能全球治理高级别会议全体会议在上海举办,推动智能向善造福全人类

2024 年 7 月 4 日&#xff0c;2024 世界人工智能大会暨人工智能全球治理高级别会议-全体会议在上海世博中心举办。联合国以及各国政府代表、专业国际组织代表&#xff0c;全球知名专家、企业家、投资家 1000 余人参加了本次会议&#xff0c;围绕“以共商促共享&#xff0c;以善…

搜维尔科技:如何使用 SenseGlove Nova 加速手部运动功能的恢复

District XR 的VR 培训 5 年多来&#xff0c;District XR 一直在为最大的工业公司创建 VR 和 AR 项目。 客户&#xff1a;District XR 客户代表&#xff1a;尼古拉沃尔科夫 他的角色&#xff1a;District XR 首席执行官 面临解决的挑战 该公司正在寻找一种方法来加速身体伤…

JavaScript——while类型

目录 任务描述 相关知识 while类型 编程要求 任务描述 质数的定义如下&#xff1a;大于1的自然数&#xff0c;且除了1和本身外没有别的因数。如2、3、5、7。 本关任务&#xff1a;利用循环结构求质数的和。 相关知识 在选择结构中&#xff0c;条件会被测试一次&#xff…

JAVA进阶学习10

文章目录 一、创建不可变集合二、Stream流2.1 Stream流的获取2.1 Stream流的中间方法2.2 Stream流的终结方法 一、创建不可变集合 意义&#xff1a;如果一个集合中的数据在复制或使用过程中不能修改&#xff0c;或者被其他对象调用时不能改变内部数据&#xff0c;即增加数据的安…