Student wx = new Student();
这行代码,实际上做了三件事:
理解这三步非常重要。其关键点就在于:wx中存储的不是对象本身,而是对象的地址。
PS:对象和变量都是存放在内存中的
在面向对象的语言中,对象的地址又被称之为引用(reference)。(面向过程的语言,比如C语言中,称之为“指针”)
眼见为实,C#中允许使用
演示:使用&运算符……
因为引用类型变量并不存放实质性数据,所以当我们运行这一行代码的时候:
wx.age = 18;
18并没有存放在wx中,而是存放在wx(通过内存地址)所指向的对象中,如图所示:
取值的时候也一样:
我们需要通过变量里面存储的内存地址,找到相应的对象,然后才能在对象中拿到值。
如果要改变变量本身的值,只有一种办法,重新给它赋值一个对象:
wx = new Student();*&演示:wx中存储的地址发生了改变。
如果一个类,实例化之后的对象,不会直接存放在变量(栈)中,而是存放在另外的地方(堆),它就是引用类型;相对应的,就是值(value)类型
如果一个变量,存放的是对象的地址,而不是对象本身,这个变量就是引用类型变量;相对应的,就是值类型变量。
struct Student { public int age;
引用类型:值类型以外,或者由class/interface等定义……(注意:数组不是基本类型,而是引用类型)
&和*演示:值类型中存放的是值
int i = 18;
Student wx = new Student();
同时注意,如果wx变量没有指向任何对象的话(即*&wx的值为0x00000……),我们可以说它的值为null 。
null值上不能进行任何运算,由于对象为null值而报的错误NullReferenceException是程序中最常见的错误。
Student wx = null; wx.age = 18;
值类型变量的值不能为null,如果没有为其赋值,它会有一个默认值(参考:默认值表)。
int age = null; //编译错误
理解值类型和引用类型的区别有什么作用呢?
我们来看这个代码:
Student wx = new Student(); wx.age = 18; Student clone = wx; -- 这里是把wx的什么赋值给了clone? clone.age = 20; Console.WriteLine(wx.age);
@想一想@:输出的结果是什么?为什么呢?
运行之后我们发现wx.age变成了20,因为 :
Student clone = wx; 这一行代码,实际上是把变量wx中存放的Student对象地址赋值给了clone,从而让clone变量中也存放了wx的对象地址。
所以,当我们修改clone.age的时候,实际上修改的是new Student()对象中的Age。而由于wx和clone都执行了new Student(),所以当我们获取wx.age的时候,获取的也是clone.age的值。
演示:wx.age仍然是18
Java/JavaScript中没有struct,只能这样演示:
int i = 18; int j = i; -- 注意这一行代码 j = 20; Console.WriteLine(i); -- i的值是18还是20?
细想还是有一点问题的:因为j是被完全重新赋值,不是在修改j上的值。
上述代码完全转化成引用类型的话,应该这样:
Student wx = new Student(); wx.age = 18; Student clone = wx; clone = new Student(); clone.age = 20; Console.WriteLine(wx.age); //还是18,体现不出来引用&值类型的区别
@想一想@:为什么会是这样的结果呢?
有些资料会用方法参数传递来演示:值类型和引用类型。
方法默认传递方式是值传递:传递的是变量的值的“副本”,所以方法不改变变量本身
static void grow(ref int age) { age++; Console.WriteLine(age); }
调用该方法:
Student atai = new Student(); atai.age = 18; //值传递:传递是一个“值”,或者理解成:变量的值的副本 grow(atai); Console.WriteLine(atai.age);
这和变量的赋值是一样的道理。
但是,引用传递 呢?
注意:Java和JavaScript里面没有真正的引用传递,你以为的引用传递,实际上是引用类型的值传递!
static void grow(Student student)//Student是一个引用类型而已 { student.age++; Console.WriteLine(student.age); }
调用这个方法时,一样是把方法外面的变量(地址)值,拷贝一份给方法参数而已。
真正的引用传递,只有C#里面才有。
多快好省!前端后端,线上线下,名师精讲
更多了解 加: