C++编程:进阶阶段—4.2对象

news2025/3/11 16:32:33

目录

 

4.2 对象特征

4.2.1 构造函数和析构函数

4.2.2 构造函数的分类

4.2.3 拷贝函数调用时机

4.2.4 构造函数调用规则

4.2.5 深拷贝与浅拷贝

4.2.6 初始化列表

4.2.7 类对象作为类成员

4.2.8 静态成员

4.2.9 成员变量和成员函数的存储

4.2.10 this指针

4.2.11 空指针访问成员函数

4.2.12 const修饰成员函数


4.2 对象特征

对象的初始化和清理:C++中,每个对象都有初始设置和对象销毁前的清理数据的设置。

4.2.1 构造函数和析构函数

C++中利用构造函数和析构函数对对象进行初始化和清理。这两个函数会被编译器自动调用,完成对象的初始化和清理。如果程序员不提供构造和析构,编译器会提供构造函数和析构函数,但是是空的。

构造函数:创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。

语法:类名(){}

1.构造函数,没有返回值也不写void;

2.函数名与类名相同;

3.构造函数可以有参数,因此可以发生重载;

4.程序在调用对象时会自动调用构造,无须手动调用,且只调用一次。

析构函数:对象销毁前系统自动调用,执行一些清理工作。

语法:~类名(){}

1.析构函数,没有返回值也不写void;

2.函数名与类名相同,在函数名前加上符号~;

3.析构函数不可以有函数,因此不可以发生重载;

4.程序在对象销毁前会自动调用析构,无须手动调用,且只调用一次。

代码如下:

#include <iostream>
using namespace std;

class Person
{
public:
    //构造函数 初始化对象
    Person()
    {
        cout<<"Person构造函数的调用"<<endl;
    }

    //析构函数 销毁/清理对象
    ~Person()
    {
        cout<<"Person析构函数的调用"<<endl;
    }
};

void test01()
{
    Person p;//栈上的数据,该函数执行完后,p这个对象会被释放
}

int main()
{
    //对象的初始化和清理

    test01();
    Person p;

    system("pause");
    return 0;
}

输出如下:

4.2.2 构造函数的分类

按参数分:有参构造、无参构造;

按类型分:普通构造、拷贝构造。

调用方式:括号法、显示法、隐式转换法。

代码如下:

#include <iostream>
using namespace std;

//构造函数发分类及调用
class Person
{
public:
    //无参(默认)构造
    Person()
    {
        cout<<"Person的无参构造函数的调用"<<endl;
    }

    //有参构造
    Person(int a)
    {
        age=a;
        cout<<"Person的有参构造函数的调用"<<endl;
    }

    //拷贝构造函数(将Person p的属性拷贝过来)
    Person(const Person &p)
    {
        age=p.age;
        cout<<"Person的拷贝构造函数的调用"<<endl;
    }

    ~Person()
    {
        cout<<"Person析构函数的调用"<<endl;
    }

private:
    int age;
};

void test01()
{
    //调用:括号法
    cout<<"括号法调用构造函数:"<<endl;
    Person p1;//默认构造函数调用,不用加括号,编译器会认为Person p1();是一个函数声明。
    Person p2(21);//有参构造函数调用
    Person p3(p2);//拷贝构造函数调用

    //调用:显示法
    cout<<"显示法调用构造函数:"<<endl;
    Person p4;
    Person p5=Person(21);//有参构造
    Person P6=Person(p5);//拷贝构造

    Person(21);//表示一个匿名对象,在等式左边的P2就是给他取的名字,匿名对象执行后会立即回收。
    cout<<"匿名对象清理后执行了这句代码"<<endl;

    //PS:不要用拷贝构造 初始化匿名对象,编译器会认为Person(p3);是一个对象声明Person p3;
    //Person(p3);


    //调用:隐式转换法
    cout<<"显示法调用构造函数:"<<endl;
    Person p7=21;//有参构造
    Person p8=p7;//拷贝构造
}

int main()
{
    test01();
    return 0;
}

输出如下:

4.2.3 拷贝函数调用时机

  • 使用一个已经创建完毕的对象来初始化一个新对象;
  • 值传递的方式给函数参数传值;
  • 以值方式返回局部对象。

代码如下:

#include <iostream>
using namespace std;

//拷贝构造函数调用时机
class Person
{
public:
    //无参(默认)构造
    Person()
    {
        cout<<"Person的无参构造函数的调用"<<endl;
    }

    //有参构造
    Person(int a)
    {
        age=a;
        cout<<"Person的有参构造函数的调用"<<endl;
    }

    //拷贝构造函数
    Person(const Person &p)
    {
        age=p.age;
        cout<<"Person的拷贝构造函数的调用"<<endl;
    }

    ~Person()
    {
        cout<<"Person析构函数的调用"<<endl;
    }

    int age;
};

//使用一个已经创建完毕的对象来初始化一个新对象
void test01()
{
    cout<<"test01函数调用"<<endl;
    Person p1(21);
    Person p2(p1);
    cout<<"p2的年龄为:"<<p2.age<<endl;
}

//值传递的方式给函数参数传值
void doWork(Person p)
{

}

void test02()
{
    cout<<"test02函数调用"<<endl;
    Person p;
    doWork(p);//这里传入的p和dowork中的p不一样
}

//以值方式返回局部对象
Person doWork2()
{
    Person p1;
    cout<<"p1的地址为:"<<(long long)&p1<<endl;
    return Person(p1);//直接返回p1则不会调用拷贝函数,因为编译器自动做了优化(可以看到p1和p的地址一样)
}

void test03()
{
    cout<<"test03函数调用"<<endl;
    Person p=doWork2();
    cout<<"p的地址为:"<<(long long)&p<<endl;
}

int main()
{
    test01();

    test02();

    test03();

    return 0;
}

输出如下:

4.2.4 构造函数调用规则

默认情况下,C++编译器至少给类添加三个函数;

  1. 1.默认构造函数(无参,函数体为空)
  2. 2.默认析构函数(无参,函数体为空)
  3. 3.默认拷贝构造函数,对属性进行值拷贝

调用规则:

  • 如果用户定义了有参构造函数,则编译器不提供默认无参构造,但会提供默认拷贝构造
  • 如果用户定义了拷贝构造函数,则编译器不再提供其他构造函数

代码如下:

#include <iostream>
using namespace std;

class Person
{
public:
    // Person()
    // {
    //     cout<<"person的默认构造函数"<<endl;
    // }
    Person(int a)
    {
        age=a;
        cout<<"Person的有参构造函数的调用"<<endl;
    }
    // Person(const Person &p)
    // {
    //     age=p.age;
    //     cout<<"Person的拷贝构造函数的调用"<<endl;
    // }

    ~Person()
    {
        cout<<"Person析构函数的调用"<<endl;
    }

    int age;
};

// void test01()
// {
//     Person p;
//     p.age=18;

//     Person p2(p);
//     cout<<"p2的年龄为:"<<p2.age<<endl;
// }

void test02()
{
    Person p(28);
    Person p2(p);
    cout<<"p2的年龄为:"<<p2.age<<endl;
}

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

输出如下:用户定义了拷贝构造函数

输出如下:用户没有定义拷贝构造函数

错误示例:用户定义了有参构造,但没有定义无参(默认)构造,则编译器也不会提供默认构造,此时调用默认构造则会报错。

输出如下:用户只定义了有参构造,则编译器依然或提供拷贝构造

4.2.5 深拷贝与浅拷贝

浅拷贝:编译器提供的拷贝函数,简单的赋值拷贝操作;

缺点:容易导致堆区的重复释放,利用深拷贝解决。

深拷贝:在堆区重新申请空间,进行拷贝操作,而不是与被拷贝的指针指向相同的空间。

PS:如果属性有在堆区开辟的,一定要自己定义拷贝构造函数,防止浅拷贝中出现的问题。

代码如下:

#include <iostream>
using namespace std;

class Person
{
public:
    Person()
    {
        cout<<"person的默认构造函数"<<endl;
    }
    Person(int a,int h)
    {
        age=a;
        height=new int(h);
        cout<<"Person的有参构造函数的调用"<<endl;
    }
    //自己实现拷贝构造函数,解决浅拷贝的问题
    Person(const Person &p)
    {
        age=p.age;
        height=p.height;//编译器写的(浅拷贝)
        height= new int(*p.height);//深拷贝操作,另外开辟空间
        cout<<"Person的拷贝构造函数的调用"<<endl;
    }

    ~Person()
    {
        //析构的作用,将堆区new的数据手动释放
        if(height!=NULL)//若指针不为空,则需要释放
        {
            delete height;//P2先释放,完了之后P也需要释放,但两个对象的指针操作的是同一个堆区中的地址,造成重复释放的非法操作,因此会报错
            height=NULL;//防止野指针出现,将指针置空
        }
        cout<<"Person析构函数的调用"<<endl;
    }

    int age;
    int * height;
};

void test01()
{
    Person p(28,160);

    Person p2(p);
    cout<<"p2的年龄为:"<<p2.age<<" 身高为:"<<*p2.height<<endl;
}

int main()
{
    test01();

    return 0;
}

输出如下:

4.2.6 初始化列表

作用:C++提供了初始化列表语法,用来初始化属性。

语法:构造函数():属性1(值1),属性2(值2)...{}

代码如下:

#include <iostream>
using namespace std;

class Person
{
public:
    //传统初始化操作
    // Person(int a,int b,int c)
    // {
    //     A=a;
    //     B=b;
    //     C=c;
    // }

    //初始化列表赋初值
    //Person():A(1),B(2),C(3){}
    Person(int a,int b,int c):A(a),B(b),C(c){}
    int A;
    int B;
    int C;
};

void test01()
{
    //Person p(10,20,30);//传统赋值
    Person p(1,2,3);//列表赋值
    cout<<"A="<<p.A<<endl;
    cout<<"B="<<p.B<<endl;
    cout<<"C="<<p.C<<endl;

}

int main()
{
    test01();
    return 0;
}

输出如下:

4.2.7 类对象作为类成员

C++中类的成员可以是另一个类的对象,称为对象成员。

注意对象作为成员时,两种对象的构造和析构函数的顺序。(先构造其他类,再构造本类,先析构本类,再析构其他类)

代码如下:

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

//对象成员
class Phone
{
public:
    //手机品牌
    string PName;
    Phone(string pname)
    {
        cout<<"Phone的构造函数的调用"<<endl;
        PName=pname;
    }

    ~Phone()
    {
        cout<<"Phone析构函数的调用"<<endl;
    }
};

class Person
{
public:
    //P(pname)相当于Phone P=pname; 隐式转换法
    Person(string name,string pname):Name(name),P(pname)
    {
        cout<<"Person的构造函数的调用"<<endl;
    }


    ~Person()
    {
        cout<<"Person析构函数的调用"<<endl;
    }

    string Name;
    Phone P;
};

void test01()
{
    Person p("张三","iPhone18");

    cout<<p.Name<<"拿着"<<p.P.PName<<endl;
}



int main()
{
    test01();

    return 0;
}

输出如下:

4.2.8 静态成员

静态成员是指在成员变量和成员函数卡加static关键字,静态成员都有三种访问权限。

静态成员变量:

  • 所有对象共享同一份数据
  • 在编译阶段分配内存(程序运行前)
  • 类内声明,类外初始化

静态成员函数

  • 所有对象共享同一个函数
  • 静态成员函数只能访问静态成员变量

代码如下:

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

//静态成员
class Person
{
public:
    //静态成员变量
    static int A;//类内声明
    int B;

    //静态成员函数
    static void func()
    {
        A=44;
        //B=22;//静态成员函数访问非静态成员变量,报错,无法区分是哪个对象的B
        cout<<"静态成员函数调用"<<endl;
    }
};

//类外初始化
int Person::A=100;

void test01()
{
    Person p;
    cout<<p.A<<endl;

    Person p2;
    p2.A=200;
    
    //所有对象共享同一份数据,因此有两种访问方式:通过对象访问;通过类名访问
    cout<<p.A<<endl;
    cout<<Person::A<<endl;
}

void test02()
{
    //两种访问方式:通过对象访问;通过类名访问
    Person p;
    p.func();

    Person::func();
    cout<<p.A<<endl;
}

int main()
{
    test01();
    test02();
    return 0;
}

输出如下:

错误示例:静态成员函数访问非静态成员变量

4.2.9 成员变量和成员函数的存储

类内的成员变量和成员函数分开存储,只有非静态成员变量才属于类的对象上的。

代码如下:

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

//静态成员
class Person1
{

};

class Person2
{
    int A;//非静态成员变量 
};

class Person3
{
    int A;
    static int B;//静态成员变量
};

int Person3::B=9;

class Person4
{
    int A;
    static int B;
    void func(){}//非静态成员函数
};

class Person5
{
    int A;
    static int B;
    void func(){}//非静态成员函数
    static void func2(){};
};

void test01()
{
    Person1 p1;
    //空对象占用内存为1,为了区分空对象占内存的位置,每个空对象有一个唯一的地址
    cout<<"size of p1="<<sizeof(p1)<<endl;

    Person2 p2;
    //有非静态成员变量,占4字节  属于类的对象上的数据
    cout<<"size of p2="<<sizeof(p2)<<endl;

    Person3 p3;
    //有静态成员变量  不属于类的对象上的数据
    cout<<"size of p3="<<sizeof(p3)<<endl;

    Person4 p4;
    //非静态成员函数  不属于类的对象上的数据
    cout<<"size of p4="<<sizeof(p4)<<endl;

    Person5 p5;
    //静态成员函数  不属于类的对象上的数据
    cout<<"size of p5="<<sizeof(p5)<<endl;
}

int main()
{
    test01();

    return 0;
}

输出如下:

4.2.10 this指针

每一个非静态成员函数只会产生一个函数实例,所有同类中的多个对象会公用一块代码。

C++提供this指针来指向被调用的成员函数所属的对象。this指针是隐含每一个非静态成员函数内的一种指针,不需要定义,直接使用即可。

用途:

  • 当形参和成员变量同名时,用this指针来区分
  • 在类的非静态成员函数中返回对象本身,可使用return *this。

PS:用Person&定义返回值类型,是因为可以一直对同一个空间操作,用Person定义返回值类型表示值返回,会复制一份新的数据(按照本体p2创建了新的数据,而不是返回的p2本体),调用了拷贝构造函数。

代码如下:

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

class Person
{
public:
    int age;
    Person(int age)
    {
        //age=age;//报错
        //this指针指向被调用的成员函数所属的对象p1
        this->age=age;
    }
//用Person&定义返回值类型,是因为可以一直对同一个空间操作,用Person定义返回值类型表示值返回,会复制一份新的数据(按照本体p2创建了新的数据,而不是返回的p2本体),调用了拷贝构造函数
     Person& PersonAddAge(Person &p)
     {
        this->age+=p.age;
        //this指向p2的指针,*p2指向p2本体
        return *this;
     }
};

//解决名称冲突
void test01()
{
    Person p1(18);
    cout<<p1.age<<endl;
}

//用*this 返回对象本身
void test02()
{
    Person p1(31);

    Person p2(31);
    p2.PersonAddAge(p1);
    cout<<p2.age<<endl;
    p2.PersonAddAge(p1).PersonAddAge(p1);//用this*返回才能链式追加
    cout<<p2.age<<endl;

}

int main()
{
    test01();
    test02();
    return 0;
}

输出如下:

错误示例:名称冲突,形参和属性名相同时,不能输出正确结果

4.2.11 空指针访问成员函数

C++中空指针可以调用成员函数,但需要注意有没有用this指针。如果用到this指针,需要加以判断保证代码的健壮性。

代码如下:

#include <iostream>
using namespace std;

//空指针调用成员函数
class Person
{
public:
    void showClassName()
    {
        cout<<"this is person class"<<endl;
    }

    void showPersonAge()
    {
        if(this==NULL)
        {
            return;
        }
        //传入指针为空,报错  在前面加一个空指针的判断
        cout<<"age="<<this->age<<endl;
    }

    int age;
};

void test01()
{
    Person *p=NULL;
    p->showClassName();
    p->showPersonAge();
}

int main()
{
    test01();
    return 0;
}

输出如下:

错误示例:用空指针访问属性,图中age,默认是this->age,而访问时用的空指针,this为空所以不能指向正确的对象的属性。

4.2.12 const修饰成员函数

常函数:

  • 成员函数后加const后称为常函数;
  • 常函数内不可用修改成员属性;
  • 成员属性声明时加关键词mutable后,在常函数中依然可以修改

常对象:

  • 声明对象前加const称该对象为常对象;
  • 常对象不允许修改指针指向的值;

  • 常对象只能调用常函数

代码如下:

#include <iostream>
using namespace std;

//常函数
class Person
{
public:
    //this指针的本质是一个指针常量Person * const this 指针的指向是不可修改的
    //后面加的const相当于const Person * const this,使this指向的值也不可修改
    void showPerson() const
    {
        this->b=99;
        //this=NULL;//this的指针指向不能修改
        cout<<"this is person class"<<endl;
    }
    Person(){}//不写默认构造函数会报错实例化的常对象没有初始化

    void func(){}
    int age;
    mutable int b;
};

void test01()
{
    Person p;
    p.showPerson();
}

void test02()
{
    const Person p;
    //p.age=99;//报错 常对象不允许修改指针指向的值
    p.b=88;
    p.showPerson();
    //p.func();//报错 常对象不能调用非常函数
}

int main()
{
    test01();
    test02();
    return 0;
}

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

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

相关文章

TensorFlow.js 全面解析:在浏览器中构建机器学习应用

TensorFlow.js 全面解析&#xff1a;在浏览器中构建机器学习应用 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;可以分享一下给大家。点击跳转到网站。 https://www.captainbed.cn/ccc 文章目录 TensorFlow.js 全面解析&#x…

CI/CD—Jenkins配置Poll SCM触发自动构建

Poll SCM简介 在 Jenkins 等持续集成工具中&#xff0c;“Poll SCM” 是一种用于轮询软件配置管理&#xff08;SCM&#xff09;系统以检查代码变更的机制&#xff0c;以下是对它的详细介绍&#xff1a; 作用 “Poll SCM” 允许 Jenkins 定期检查指定的 SCM 系统&#xff08;如 …

AI与SEO关键词智能解析

内容概要 人工智能技术正重塑搜索引擎优化的底层逻辑&#xff0c;其核心突破体现在关键词解析维度的结构性升级。通过机器学习算法对海量搜索数据的动态学习&#xff0c;AI不仅能够识别传统TF-IDF模型中的高频词汇&#xff0c;更能捕捉语义网络中隐含的关联特征。下表展示了传…

STM32之BKP

VBAT备用电源。接的时候和主电源共地&#xff0c;正极接在一起&#xff0c;中间连接一个100nf的电容。BKP是RAM存储器。 四组VDD都要接到3.3V的电源上&#xff0c;要使用备用电池&#xff0c;就把电池正极接到VBAT&#xff0c;负极跟主电源共地。 TEMPER引脚先加一个默认的上拉…

c++的基础排序算法

一、快速排序 1. 选择基准值&#xff08;Pivot&#xff09; 作用 &#xff1a;从数组中选择一个元素作为基准&#xff08;Pivot&#xff09;&#xff0c;用于划分数组。常见选择方式 &#xff1a; 固定选择最后一个元素&#xff08;如示例代码&#xff09;。随机选择&#xf…

基于Spring3的抽奖系统

注&#xff1a;项目git仓库地址&#xff1a;demo.lottery 小五Z/Spring items - 码云 - 开源中国 目录 注&#xff1a;项目git仓库地址&#xff1a;demo.lottery 小五Z/Spring items - 码云 - 开源中国 项目具体代码可参考仓库源码&#xff0c;本文只讲解重点代码逻辑 一…

基于qiime2的16S数据分析全流程:从导入数据到下游分析一条龙

目录 创建metadata 把数据导入qiime2 去除引物序列 双端合并 &#xff08;dada2不需要&#xff09; 质控 &#xff08;dada2不需要&#xff09; 使用deblur获得特征序列 使用dada2生成代表序列与特征表 物种鉴定 可视化物种鉴定结果 构建进化树&#xff08;ITS一般不构建进化树…

【Linux系统编程】基本IO函数

目录 1、open 函数2、create 函数3、write 函数4、read 函数5、lseek 函数6、access 函数7、unlink 函数8、remove 函数9、fcntl 函数写锁互斥锁示例读锁共享锁示例 1、open 函数 头文件 #include<sys/types.h> #include<sys/stat.h>#include<fcntl.h>…

Deepseek应用技巧-chatbox搭建前端问答

目标&#xff1a;书接上回&#xff0c;由于本地私有化部署了deepseek的大模型&#xff0c;那怎么能够投入生产呢&#xff0c;那就必须有一个前端的应用界面&#xff0c;好在已经有很多的前人已经帮我们把前段应用给搭建好了&#xff0c;我们使用就可以啦&#xff0c;今天我们就…

OpenAI API模型ChatGPT各模型功能对比,o1、o1Pro、GPT-4o、GPT-4.5调用次数限制附ChatGPT订阅教程

本文包含OpenAI API模型对比页面以及ChatGPT各模型功能对比表 - 截至2025最新整理数据&#xff1a;包含模型分类及描述&#xff1b;调用次数限制&#xff1b; 包含模型的类型有&#xff1a; Chat 模型&#xff08;如 GPT-4o、GPT-4.5、GPT-4&#xff09;专注于对话&#xff0c…

Fast DDS Security--秘钥交换

Fast DDS Security模块中默认使用Diffie-Hellman算法进行秘钥交换。Diffie-Hellman 算法&#xff08;简称 DH 算法&#xff09;是一个非常重要的加密协议&#xff0c;用于在不安全的通信通道中安全地交换密钥。该算法通过利用数学中的离散对数问题来生成共享密钥&#xff0c;使…

从0开始的操作系统手搓教程33:挂载我们的文件系统

目录 代码实现 添加到初始化上 上电看现象 挂载分区可能是一些朋友不理解的——实际上挂载就是将我们的文件系统封装好了的设备&#xff08;硬盘啊&#xff0c;SD卡啊&#xff0c;U盘啊等等&#xff09;&#xff0c;挂到我们的默认分区路径下。这样我们就能访问到了&#xff…

基于muduo+mysql+jsoncpp的简易HTTPWebServer

一、项目介绍 本项目基于C语言、陈硕老师的muduo网络库、mysql数据库以及jsoncpp&#xff0c;服务器监听两个端口&#xff0c;一个端口用于处理http请求&#xff0c;另一个端口用于处理发送来的json数据。 此项目在实现时&#xff0c;识别出车牌后打包为json数据发送给后端服务…

【Go学习实战】03-2-博客查询及登录

【Go学习实战】03-2-博客查询及登录 读取数据库数据初始化数据库首页真实数据分类查询分类查询测试 文章查询文章查询测试 分类文章列表测试 登录功能登录页面登录接口获取json参数登录失败测试 md5加密jwt工具 登录成功测试 文章详情测试 读取数据库数据 因为我们之前的数据都…

《Python实战进阶》No20: 网络爬虫开发:Scrapy框架详解

No20: 网络爬虫开发&#xff1a;Scrapy框架详解 摘要 本文深入解析Scrapy核心架构&#xff0c;通过中间件链式处理、布隆过滤器增量爬取、Splash动态渲染、分布式指纹策略四大核心技术&#xff0c;结合政府数据爬取与动态API逆向工程实战案例&#xff0c;构建企业级爬虫系统。…

Linux:多线程(单例模式,其他常见的锁,读者写者问题)

目录 单例模式 什么是设计模式 单例模式介绍 饿汉实现方式和懒汉实现方式 其他常见的各种锁 自旋锁 读者写者问题 逻辑过程 接口介绍 单例模式 什么是设计模式 设计模式就是一些大佬在编写代码的过程中&#xff0c;针对一些经典常见场景&#xff0c;给定对应解决方案&…

【氮化镓】高输入功率应力诱导的GaN 在下的退化LNA退化

2019年,中国工程物理研究院电子工程研究所的Tong等人基于实验与第一性原理计算方法,研究了Ka波段GaN低噪声放大器(LNA)在高输入功率应力下的退化机制。实验结果表明,在27 GHz下施加1 W连续波(CW)输入功率应力后,LNA的增益下降约1 dB,噪声系数(NF)增加约0.7 dB。进一…

Javaweb后端文件上传@value注解

文件本地存储磁盘 阿里云oss准备工作 阿里云oss入门程序 要重启一下idea&#xff0c;上面有cmd 阿里云oss案例集成 优化 用spring中的value注解

git规范提交之commitizen conventional-changelog-cli 安装

一、引言 使用规范的提交信息可以让项目更加模块化、易于维护和理解&#xff0c;同时也便于自动化工具&#xff08;如发布工具或 Changelog 生成器&#xff09;解析和处理提交记录。 通过编写符合规范的提交消息&#xff0c;可以让团队和协作者更好地理解项目的变更历史和版本…

Java/Kotlin逆向基础与Smali语法精解

1. 法律警示与道德边界 1.1 司法判例深度剖析 案例一&#xff1a;2021年某游戏外挂团伙刑事案 犯罪手法&#xff1a;逆向《王者荣耀》通信协议&#xff0c;修改战斗数据包 技术细节&#xff1a;Hook libil2cpp.so的SendPacket函数 量刑依据&#xff1a;非法经营罪&#xff…