[C++核心编程-02]----C++引用详解和使用方法分析

news2024/9/28 7:29:07

前言

        在C++中,引用是一个别名,它允许将一个已存在的变量或对象用不同的名称来访问。引用在定义时必须初始化,并且一旦初始化就不能再绑定其他对象,因此引用在声明时被初始化后就不能再改变引用对象。引用使用&符号进行声明。

        引用的定义形式如下:

Type& ref = variable;

        其中,Type是引用所引用对象的类型,ref是引用的名称,variable是引用所绑定的变量或对象。 

正文

01-引用简介

        C++中的引用是一个别名,可以用来访问已存在的变量或对象,相当于给变量起一个别名。引用在定义时必须初始化,且初始化后不可再绑定其他对象,即引用在声明时被初始化后就不能再改变引用对象。引用使用&符号进行声明。

        引用主要有以下特点和使用方法:

        a、别名: 引用本质上是对一个已存在对象的别名,可以通过引用来操作原始对象,实现对原始对象的直接改变。 

        b、必须初始化: 定义引用时必须进行初始化,且一旦初始化就不能再绑定其他对象。

        c、传递和修改函数参数: 可以通过引用将变量传递给函数,函数可以修改引用指向的变量,实现“引用参数”的功能,避免传递大量数据的复制。

        d、返回引用: 函数可以返回引用类型,从而可以通过函数返回值改变对象的值。

        e、方便修改对象值: 通过引用可以直接修改对象的值而无需通过指针间接修改。

        f、常引用: 通过const修饰的引用称为常引用,只能读取对象值,不能修改。

        g、注意事项: 使用引用时需要注意避免悬空引用、引用指向临时变量等问题。

02-引用的基本语法

        引用在C++中的创建需要遵循以下基本语法规则:

        a、定义引用变量:引用是通过在声明时在变量名前加上&符号来创建的,表示这是一个引用变量。

        b、初始化引用:在定义引用时必须进行初始化,即需要将引用绑定到一个已存在的变量或对象上。一旦引用被初始化后,就不能再绑定其他对象。

        c、使用引用:通过引用可以直接操作原始对象,修改引用也会影响原始对象的值。可以像使用普通变量一样使用引用。

        下面给出一个示例代码,展示引用的创建过程:在这个示例中,首先定义了一个整型变量x,然后创建了一个整型引用ref,引用了变量x。通过引用ref修改了原始变量x的值,并输出了修改前后的结果,演示了引用的创建和使用过程。

#include <iostream>
using namespace std;

int main() {
    int x = 5;  // 定义一个整型变量x,并赋初值为5
    int& ref = x;  // 创建一个整型引用ref,引用变量x

    cout << "原始变量x的值为:" << x << endl;  // 输出原始变量x的值
    cout << "引用所绑定的对象的值为:" << ref << endl;  // 输出引用所绑定对象的值

    ref = 10;  // 通过引用修改原始变量x的值

    cout << "修改后,原始变量x的值为:" << x << endl;  // 输出修改后的原始变量x的值

    system("pause");
    return 0;
}

        下面给出具体代码,用于分析引用基本语法使用过程:在这个示例中,引用b和变量a共享相同的内存空间,因此当通过引用b修改值时,也会影响到原始变量a的值。这展示了引用的一个重要特性:通过引用可以直接对原始变量进行操作,而不需要操作副本。引用在C++中的这种功能可以简化对变量的处理,提高代码的可读性和效率。这个示例通过引用实现了对原始变量的修改和输出,展示了引用的使用方式。

#include<iostream>
using namespace std;

int main()
{
	// 引用的基本语法  相同数据类型  &别名 = 原名

	int a = 10;

	// 创建引用
	int &b = a;

	b = 100;  //因为a和b是同时操作的同一个内存,因此,当改变b时,a也会改变

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

	system("pause");
	return 0;

}

        示例运行结果如下图所示:

03-引用的注意事项

        引用在C++中是一个非常有用的特性,但同时也需要注意以下几个重要的事项:

        a、引用必须在定义时初始化:引用必须在定义的同时进行初始化,即在创建引用时必须将其绑定到某个变量上。例如int &b = a;,这里的b就是引用,它必须在定义时就绑定到变量a上。

        b、引用与原变量共享内存空间:引用本质上是原变量的别名,它们共享同一块内存空间。因此,对引用的操作会直接影响原变量的值,反之亦然。这种共享内存空间的特性是引用的重要特点。

        c、引用不能重新绑定:一旦引用绑定到某个变量上,就不能再重新绑定到其他变量。引用的绑定是一种一次性的操作,不能修改。

        d、避免悬空引用:悬空引用是指引用的目标对象已经被销毁,但引用仍然存在。如果在这种情况下使用引用,会导致未定义行为。因此,使用引用时要确保目标对象的生命周期覆盖了引用的使用范围。

        e、使用引用要小心指针:引用与指针类似,但也有不同之处。引用是一个别名,可以简化代码和提高可读性,但指针可以在运行时进行重新赋值和指向不同的对象。因此,需要根据实际情况选择使用引用还是指针。

        注:引用必须初始化。引用在初始化后,不可以进行更改。

#include <iostream>
using namespace std;

int main() {
    int a = 10;
    int &b = a; // 初始化引用b绑定到变量a
    int c = 20;

    b = c; // 修改a的值为20,因为b是a的引用

    cout << "a = " << a << endl; // 输出20
    cout << "b = " << b << endl; // 输出20

    // 尝试重新绑定引用
    int d = 30;
    // int &ref = d; // 这样会报错,引用不能重新绑定

    return 0;
}

        下面给出具体代码,用于分析引用的注意事项过程,这个示例代码主要演示了引用的两个注意事项:

        a、引用必须在定义时初始化:在代码中,定义了一个int a = 10;的变量a,并尝试定义一个引用int &b;但这句代码是错误的,因为引用在定义时必须初始化。正确的做法是int &b = a;,将引用b初始化绑定到变量a上。

        b、引用在初始化后不可以进行更改:在代码中,虽然进行了b = c;的赋值操作,但这并不是将b改成c的引用,而是将a的值修改为了c的值。由于引用本质上是指向了a的地址,所以a和b指向的地址是一样的。而c则有不同的地址。虽然地址不同,但是对应的内存单元中存储的数值可以相同。

#include<iostream>
using namespace std;

int main()
{

	int a = 10;
	// 1、引用必须初始化

//	int &b;  // 这句代码错误,必须初始化
	int  &b = a;

	// 2、引用在初始化后,不可以进行更改
	int c = 20;
	b = c;  // 这里并没有将b改成c的引用,只是一个赋值的操作,此时b指向的还是a的地址
	
	// 地址不会改变,因此可以看出,a和b的地址还是相同的,但是c和他们的地址不同,
	// 然而,虽然不同地址,但是对应的内存单元中存储的数值是可以相同的
	cout << "c = " << &c << endl;  // 0113F95C
	cout << "a = " << &a << endl;  // 0113F974
	cout << "b = " << &b << endl;  // 0113F974

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


	system("pause");
	return 0;

}

        示例运行结果如下图所示:

04-引用做函数参数

        当引用作为函数参数时,可以实现对参数的直接操作,而不是对参数值的拷贝。这可以减少内存消耗和提高程序的执行效率。引用作为函数参数的主要优点包括:

        a、避免参数拷贝开销:当传递非引用参数时,系统会自动进行值的拷贝,而将引用作为参数传递可以避免这种开销,提高程序效率。

        b、直接修改参数值:引用作为函数参数时,函数内对引用的操作会直接影响原始实参的值,这对函数的修改操作非常有用。

        c、返回多个值:引用可以作为返回多个值的方式,通过引用传递多个参数,并在函数内部修改这些参数的值。

        下面给出具体代码示例,演示引用作为函数参数的用法以及以上优点:在这个示例中,test1函数使用引用作为参数,实现了对传入参数的直接修改;test2函数演示了引用作为参数返回多个值的用法。

#include <iostream>
using namespace std;

// 传递引用作为参数,实现直接修改传入参数的值
void test1(int &n) {
    n++;
}

// 返回多个值,通过引用参数传递
void test2(int a, int b, int &sum, int &diff) {
    sum = a + b;
    diff = a - b;
}

int main() {
    int num = 10;
    int sum, diff;

    // 通过引用参数直接修改num的值
    test1(num);
    cout << "num after increment: " << num << endl; // 输出11

    // 返回多个值,通过引用参数传递
    test2(5, 3, sum, diff);
    cout << "sum: " << sum << ", diff: " << diff << endl; // 输出sum: 8, diff: 2

    return 0;
}

          下面给出代码,用于分析值传递、地址传递和引用传递三种方法的过程:这个示例演示了C++中的三种参数传递方式:值传递、地址传递和引用传递,并进行了交换函数的实现和调用。

        a、值传递:在mySwap01函数中,两个参数a和b被传递进去,但是在函数内部交换它们的值,并不会影响到实参。因此,ab的值不会发生改变。

        b、地址传递:在mySwap02函数中,使用指针作为参数,在函数内部通过地址修改实参的值。因此,通过传递变量地址,函数可以直接修改实参的值。在输出中,可以看到cd的值已经被交换。

        c、引用传递:在mySwap03函数中,引用被用作参数,实现了对实参的直接修改,而不是传递变量的拷贝。因此,引用传递和地址传递类似,都可以实现对实参的值的修改。在输出中,可以看到fe的值也已经被交换了。

        这个示例通过不同的参数传递方式演示了值传递、地址传递和引用传递的区别。值传递只是传递变量的副本,不会修改实参;地址传递通过传递指针可以修改实参的值;引用传递则直接修改实参的值,效果类似于地址传递。

#include<iostream>
using namespace std;


// 交换函数

// 1、值传递
void mySwap01(int a, int b)
{
	int temp = a;
	a = b;
	b = temp;
}
// 2、地址传递
void mySwap02(int *c, int *d)
{
	int temp = *c;   // 这里定义temp,不能定义指针,因为*c就已经是一个值,只需要将值赋给temp存储一下就行了
	*c = *d;
	*d = temp;
	cout << "c的地址" << c << endl;
	cout << "temp的地址" << &temp << endl;
}
// 3、引用传递
void mySwap03(int &f, int &e)  //这里参数列表中使用过了引用的方式传递参数,加&符号即可
{
	int temp = f;
	f = e;
	e = temp;
}

int main()
{

	int a = 10;
	int b = 20;
	mySwap01(a, b);  //值传递,形参不会修饰实参,也就是实参并不会改变
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	int c = 10;
	int d = 20;
	mySwap02(&c, &d);  //地址传递,形参修饰实参,也就是实参会改变
	cout << "c = " << c << endl;
	cout << "d = " << d << endl;

	int f = 10;
	int e = 20;
	mySwap03(f,e);  //引用传递,形参修饰实参,也就是实参会改变
	cout << "f = " << f << endl;
	cout << "e = " << e << endl;

	system("pause");
	return 0;

}

示例运行结果如下图所示:

05-引用做函数返回值

        当引用作为函数的返回值时,可以实现返回一个指向已存在变量或对象的引用,而不是复制一个新的变量。这样可以避免额外的内存开销,同时直接修改原始变量。引用作为函数返回值的主要优点包括:

        a、避免对象的拷贝:通过引用返回一个已存在的对象,避免了对对象进行复制构造,节省了内存空间和时间消耗。

        b、直接修改原始对象:返回引用可以直接修改原始对象的值或状态,而不是返回一个副本,使得函数能够对原始对象进行修改。

        c、返回多个值:引用可以作为一种返回多个值的方式,通过返回引用来返回多个对象或变量。

        下面给出代码示例,分析引用作为函数返回值的用法及以上优点:在这个示例中,getMax函数返回两个整数中较大的那个的引用,可以直接修改原始对象的值。在main函数中,通过调用getMax(a, b) = 100;实现了对ab值的直接修改,而不用再通过复杂的返回值或指针操作。

#include <iostream>
using namespace std;

// 返回引用,直接修改原始对象
int &getMax(int &num1, int &num2) {
    if(num1 > num2) {
        return num1;
    } else {
        return num2;
    }
}

int main() {
    int a = 10, b = 20;

    cout << "Initial values: a = " << a << ", b = " << b << endl;

    getMax(a, b) = 100;  // 直接修改a或b的值

    cout << "After modifying value: a = " << a << ", b = " << b << endl;

    return 0;
}

        接着给出具体代码,分析引用作为函数返回值的使用过程:

        注:不要返回局部变量的引用,因为局部变量存放在栈区。引用函数的调用可以作为左值。

        在这个示例中,展示了引用作为函数返回值的用法及需要注意的一些问题:

        a、不要返回局部变量的引用:在test01函数中,返回了一个指向动态分配的整型变量的引用。这里引发了一个潜在的问题,因为返回的指针对应的动态内存分配在堆区,但在函数结束后指针a被销毁,可能导致返回的引用指向的内存不再有效。

        b、引用函数的调用可以作为左值:在test02函数中,返回静态整型变量的引用。因为静态变量存放在全局区,可以保证其在程序整个生命周期中有效。因此,可以将引用函数调用作为左值,直接对函数返回的变量进行操作。

        在main函数中,分别调用test01test02函数返回引用,并将其赋值给引用变量refref2,然后输出它们的值。可以观察到,ref输出了正确的值,但第二次输出乱码,因为返回的引用指向的动态内存已经被释放。而ref2输出了静态变量的值,可以持续输出。最后通过test02() = 1000;方式实现对静态变量的直接修改,进而改变ref2的值。

        需要注意:使用引用作为函数返回值时,避免返回指向局部变量的引用,以防止悬空引用;可以返回静态变量或静态全局变量的引用,以保证返回值的有效性。

#include<iostream>
using namespace std;

//引用做函数的返回值

// 1、不要返回局部变量的引用,因为局部变量存放在栈区
int& test01()   //这里就是使用的引用返回
{
	int *a = new int(10);
	return *a;
}
// 2、引用函数的调用可以作为左值
int& test02()   //这里就是使用的引用返回
{
	static int a = 10;  // 变成了静态变量,在全局区,可以一直输出
	return a;
}

int main()
{
	// 调用引用返回函数
	int &ref = test01();  // 这里test01()以引用的方式返回的a,相当于a此时有一个别名,然后又定义了ref这个别名等于a,再进行输出
	cout << "ref = " << ref << endl;   // 这里就像是让局部变量做返回值,和栈区那一节很像,第一个正常输出,第二个乱码
	cout << "ref = " << ref << endl;

	int &ref2 = test02();
	cout << "ref2 = " << ref2 << endl;
	cout << "ref2 = " << ref2 << endl;

	test02() = 1000;  // 这里之后,ref2变成了1000,这里相当于做了一个a = 1000的操作,ref2是a的别名,因此也会改变

	cout << "ref2 = " << ref2 << endl;
	cout << "ref2 = " << ref2 << endl;
	

	system("pause");
	return 0;

}

        示例运行结果如下图所示:

06-引用的本质

        引用是C++中一个重要的特性,它实际上是一个别名,允许程序员使用一个变量的多个名称来访问相同的内存位置。引用的本质可以通过以下几点来解释:

        a、别名:引用本质上是变量的别名,即一个变量可以有多个名字来引用同一块内存位置。这使得程序员可以通过引用来操作同一个变量,而不是复制其值。

        b、地址操作:在底层实现上,引用是通过指针实现的。编译器在引用声明时会隐式地创建一个指针,并在使用引用时自动解引用。因此,引用的本质是通过指针实现的。

        c、提高代码可读性:引用的主要作用是提高代码的可读性和易用性。使用引用可以简化代码并减少冗余,使得代码更加清晰和易于理解。

        下面是一个代码示例,分析引用的本质和用法:在这个示例中,变量ref是变量x的引用,即refx的别名。通过不同的方式修改refx的值,可以观察到它们实际上指向同一个内存位置,因此修改任何一个变量的值都会影响另一个。

#include <iostream>
using namespace std;

int main() {
    int x = 10;
    int &ref = x;  // 引用变量ref是变量x的别名

    cout << "x = " << x << endl;  // 输出变量x的值
    cout << "ref = " << ref << endl;  // 输出引用ref的值

    x = 20;  // 修改变量x的值
    cout << "x = " << x << endl;  // 再次输出变量x的值
    cout << "ref = " << ref << endl;  // 输出引用ref的值,与变量x相同

    ref = 30;  // 通过引用修改变量x的值
    cout << "x = " << x << endl;  // 再次输出变量x的值,被修改为30
    cout << "ref = " << ref << endl;  // 输出引用ref的值,与变量x相同

    return 0;
}

        接着给出具体代码,分析引用的本质的使用过程:

        在这个示例中,展示了引用的本质是指针常量的概念。具体来说,对于引用int& ref1 = a;,实际上会被编译器转换为int* const ref = &a;,即ref是一个指针常量,指向不可变,但指向的值可以改变。

        在main函数中,定义了一个整型变量a并创建了一个引用ref1来引用这个变量。通过ref1 = 20;这一操作,实际上是在内部被转换为*ref = 20;,即通过引用修改了变量a的值。因此,在输出aref1的值时,它们都变成了20。

        在函数func中,参数ref1是一个引用,实际上是指针常量的概念。在函数内部对ref1的修改实际上是对其指向的变量进行修改,因此通过func(a);这一调用修改了变量a的值为100。

#include<iostream>
using namespace std;

//发现是引用,转换为 int* const ref = &a;
void func(int& ref1) {
	ref1 = 100; // ref是引用,转换为*ref = 100
}
int main() 
{
	/* 只需要记住引用是一个指针常量即可  int *const ref = &a
	*/

	// 引用相当于一个指针常量,对于指针常量来说,指向不可以更改,指向的值可以改变,因此引用不可更改
	int a = 10;
	//自动转换为 int* const ref = &a; 指针常量是指针指向不可改,也说明为什么引用不可更改
	
	int& ref1 = a;
	
	ref1 = 20; //内部发现ref是引用,自动帮我们转换为: *ref = 20;,一切都是在内部完成的
	
	cout << "a:" << a << endl;
	cout << "ref:" << ref1 << endl;
	
	func(a);
	
	system("pause");
	return 0;
}

        示例运行结果如下图所示:

07-常量引用

        常量引用是在引用声明中加上const修饰符的引用类型。常量引用用于限制对被引用对象的修改,即通过常量引用无法修改被引用对象的值,起到了类似于只读的作用。常量引用的本质是将被引用对象视为常量,从而在编译时就可以进行静态类型检查,以确保不会意外修改引用对象的值。

        下面是一个具体的代码示例,演示了常量引用的概念及用法:

        在这个示例中,首先定义了一个整型变量num,然后使用常量引用const int& constRef = num;来引用这个变量。常量引用限制了对num的修改,因此尝试修改constRef的值会导致编译错误。接着在main函数中输出常量引用指向变量的值,并调用函数modifyValue并传递常量引用,观察在函数内部的输出。

        函数modifyValue中的参数ref是一个常量引用,因此无法在函数内部修改其引用对象的值,只能通过该引用进行读取操作。这可以有效保护被引用对象不被意外修改,增强了程序的稳定性和安全性。

#include <iostream>
using namespace std;

void modifyValue(const int& ref) {
    // ref = 10;  // 错误:常量引用无法修改引用对象的值
    cout << "Value inside function: " << ref << endl;
}

int main() {
    int num = 5;
    const int& constRef = num;  // 常量引用,限制了对num的修改

    cout << "Value before modification: " << constRef << endl;
    // constRef = 10;  // 错误:常量引用无法修改引用对象的值
    modifyValue(constRef);  // 传递常量引用给函数

    return 0;
}

         接着给出具体代码,分析常量引用的使用过程:

        这个示例展示了常量引用的用法和作用。在函数showValue中,参数val被声明为常量引用const int& val,这意味着在函数内部无法修改val所引用的值,即无法对实参a进行修改。通过使用常量引用,可以确保在函数内部只能对被引用对象进行读取操作,而不会意外修改实参的值。

        在main函数中,定义了一个整型变量a并调用函数showValue将其传递给常量引用参数val。在函数内部打印出了val所引用的值,但无法对其进行修改。因此在最后输出a的值时,依然是初始值100,没有被修改。

#include<iostream>
using namespace std;

//打印数据函数
void showValue(const int& val) 
{
//   val  = 1000;   // 这里函数只是想要实现一个打印的操作,因此在参数列表中加入一个const来修饰,
	// 此时val便不可以进行修改,因为这是使用引用方式传递值,因此如果不加const,操作者在该函数中,
	// 进行了val重新赋值操作的话,实参a也会被改变,这就是为什么有些函数参数列表中带有const的原因
	cout << "val = " << val << endl;
}

int main()
{

	int a = 100;
	showValue(a);
	cout << "a = " << a << endl;
	
	system("pause");
	return 0;
}

        示例运行结果如下图所示:

总结

        经过上述分析,总结如下:

        引用是C++中一种重要的编程工具,可以简化代码、提高效率,并且有助于实现一些高级的编程技术。在使用引用时需要注意避免悬空引用、引用指向临时变量等问题,以确保程序的正确性和健壮性。

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

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

相关文章

打印菱形

使用拆分法&#xff1a;空格和*分开打印 #include <stdio.h> int main() { int n 0; //行数 scanf("%d", &n); int i 0; //打印上半行 for (i 0; i < n; i) { int j 0; for (j 0; j < n - i - 1;…

玩comfyui踩过的坑之使用ComfyUI_Custom_NODES_ALEKPET翻译组件问题

环境&#xff1a; 秋叶安装包&#xff0c;安装ComfyUI_Custom_NODES_ALEKPET组件或者直接下载网盘中的包&#xff0c;直接解压包到comfyui根目录/custom_nodes/&#xff0c;重启后&#xff0c;按指导文件操作。 注意&#xff1a;网盘指导包中有配置好的流程json文件&#xff0…

【011】网上鲜花商店(SSM+JSP)

【011】网上鲜花商店(SSMJSP&#xff09; 一、系统情况介绍 网上鲜花商店分为前台端和后台端&#xff0c;是致力于可以便捷购花而开发的一套系统&#xff0c;可以按照不同种类进行分类管理&#xff0c;清晰客观的展示鲜花的详情信息以及价格等等&#xff0c;适合新手学习开发…

C++多态特性详解

目录 概念&#xff1a; 定义及实现&#xff1a; 虚函数重写的两个例外&#xff1a; 1.协变&#xff1a; 2.析构函数的重写&#xff1a; final关键字&#xff1a; override关键字&#xff1a; 多态是如何实现的&#xff08;底层&#xff09;&#xff1a; 面试题&#xff1…

代码审计之浅谈RASP技术

前言&#xff1a; 想摆会烂&#xff0c;所以就落个笔吧。 其实本来是想写关于iast技术的&#xff0c;但是认真思考了下&#xff0c;感觉笔者自己本身也不太能讲清楚iast技术&#xff0c;怕误人子弟。 所以最后还是基于笔者的理解以及实际应用写一篇关于RASP技术的文章&#xf…

酷我音乐无广VIP破姐版,支持蝰蛇音效,PC端 v9.2.0.0

01 软件介绍 酷我音乐是一款优质在线音乐播放服务软件&#xff0c;拥有全面的音乐版权库存&#xff0c;中国好声音、蒙面歌王、燃烧吧少年等热门综艺的版权&#xff0c;包括无损音质选项&#xff0c;并涵盖广泛多样的音乐类型&#xff0c;如华语、英语、粤语音乐&#xff0c;以…

[暂未实现]APP签名不同保留数据覆盖安装记录

APP签名不同无法直接覆盖安装 使用adb可以卸载应用同时保留数据&#xff0c;但签名不同也无法覆盖安装&#xff08;安装原来签名的应用打开和卸载前一样&#xff09; 使用adb导出应用数据&#xff08;QQ&#xff09;db文件只有1kb&#xff0c;显然此方法也行不通

Superset二次开发之Legend功能优化

背景 Legend数据太长,影响整体图表体验,为改善用户体验,需要实现:1.数据省略展示,‘...’表示,鼠标悬停时,展示完整信息 2:文本内容从左向右滚动展示 柱状图优化 柱状图来自第三方Echarts插件,效果展示 功能核心在于红框的内容 option = {tooltip: {trigger: item,ax…

== 和 equals()区别,equals()重写问题

对于引用类型&#xff1a;比较的是两个引用是否相同&#xff08;所指的是否为同一个对象&#xff09;&#xff0c;注&#xff1a;如果两个引用所指的对象内容一样&#xff0c;但是不是同一个对象&#xff08;hashcode不一样&#xff09;&#xff0c;依然返回false&#xff0c;随…

Linux的基本指令(下)

各位大佬好 &#xff0c;这里是阿川的博客 &#xff0c; 祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 这篇博客续博主的上篇博客Linux基本指令。 07 …

美团KV存储squirrel和Celler学习

文章目录 美团在KV存储squirrel优化和改进在水平方向1、对Gossip协议进行优化 在垂直扩展方面1、forkless RDB数据复制优化2、使用多线程&#xff0c;充分利用机器的多核能力 在高可用方面 美团持久化kv存储celler优化和改进水平扩展优化1、使用bulkload进行数据导入2、线程模型…

安卓手机运行 Windows 操作系统:一

在折腾上一篇文章的时候&#xff0c;发现了一条有趣的折腾分支&#xff0c;在这台老设备上运行 Windows 操作系统。 看起来应该蛮有趣的&#xff0c;那么就折腾一下吧。 写在前面 最早知道 WoA&#xff08;Windows on ARM&#xff09; 项目&#xff0c;是 2020 看到这篇报道…

Mysql如何通过ibd文件恢复数据

Mysql ibd文件恢复注意问题 创建数据库&#xff08;随意创建&#xff09;创建数据表&#xff08;备注&#xff1a;表结构要和要恢复的表结构一致&#xff0c;row_format要和ibd文件的row_format一致&#xff0c;否则&#xff0c;会提示两者不一致。 当前row_formatdynamic&…

Day30:热帖排行、生成长图、将文件上传到云服务器、优化热门帖子列表、压力测试

热帖排行 不同的算分方式&#xff1a; 只存变化的帖子到redis中&#xff0c;每五分钟算一次分&#xff0c;定时任务 存redis 构建redis键 //统计帖子分数 //key:post:score -> value:postId public static String getPostScoreKey() {return PREFIX_POST SPLIT "…

vue2人力资源项目4路由和部门新增

组织架构路由 import layout from /layout export default {path: /department,component: layout, // 一级路由children: [{path: , // 二级路由地址为空 表示/department 显示一级路由二级路由component: () > import(/views/department),name: , // 可以用来跳转&#xf…

C#技巧之同步与异步

区别 首先&#xff0c;同步就是程序从上往下顺序执行&#xff0c;要执行完当前流程&#xff0c;才能往下个流程去。 而异步&#xff0c;则是启动当前流程以后&#xff0c;不需要等待流程完成&#xff0c;立刻就去执行下一个流程。 同步示例 创建一个窗体&#xff0c;往窗体里…

ES数据存储与查询基本原理

Elasticsearch&#xff08;ES&#xff09;简介 Elasticsearch&#xff08;ES&#xff09;是一个分布式、可扩展、近实时的搜索和分析引擎&#xff0c;它基于Lucene&#xff0c;设计用于云计算中&#xff0c;处理大规模文档检索和数据分析任务&#xff0c;常用于实现内部搜索引…

二维泊松方程(Neumann+Direchliet边界条件)有限元Matlab编程求解|程序源码+说明文本

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现&#xff0c;并提供所有案例完整源码&#xff1b;2.单元…

详解面向对象-类和对象

1.面向对象与面向过程的区别 ①面向过程 &#xff1a;关注点是在实现功能的步骤上面&#xff0c;就是分析出解决问题所需要的步骤&#xff0c;让后函数把这些步骤一步一步实现&#xff0c;使用的时候一个一个依次调用就可以。对于简单的流程是适合面向过程的方式进行的&#x…

模型全参数训练和LoRA微调所需显存的分析

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…