值类型和引用类型
应用的 区别 要记住,主要是三种区别:
1.比较
2.赋值
3.传参:
值参数:按值传递--传递实参变量存储的内容
引用参数:按引用传递--传递实参变量自身的内存地址 ref关键字
ref 直接改变内存地址 指向的数据,而不是重新开辟一个内存空间
*****引用参数,显然就是用来提取参数的引用的,参数的引用到底是个啥?就是那个数据的内存地址
*****这从英文翻译过来的,其实也挺形象的,感谢祖师爷吧,不能局限于汉语思维
输出参数:按引用传递--传递实参变量自身的内存地址 out关键字
方法内部必须为输出参数赋值
作用:可以返回值,可以返回多个结果,而return 只能返回一个结果
*****就相当于把参数又给输出回去了,成为输出参数,这翻译是不是其实还是挺形象的
*****其实思考问题的时候,要多去体会外国人的思维方式,原汁原味。不要纠结于汉语的思维
下面的例子有助于理解 值和引用的概念
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
int num01 = 100;
int num02 = 200;
//是将num01 和 num02 的地址传到Swap方法里
int area;
int perimeter;
Swap(ref num01,ref num02);
CalculateRect(num01, num02,out area , out perimeter);
//另外系统自带的例子
// int number = int.Parse("250+");
//上面这种情况显然会报错
//tryParse 第二个参数就是out 关键字 ,因此需要先定义一个变量,接收结果
int result;
// 注意多阅读提示信息,out返回了结果
//我们可以看到下面的定义,展示出来的是返回了两个结果,
//返回值:返回是否可以转换
//out:返回转换后的结果
//也就是说可以一个作为返回值,其他作为输出参数
//是不是很神奇
bool re = int.TryParse("250",out result);
//再试试下面的情况呗
bool re2 = int.TryParse("250+", out result);
}
//定义两个整数交换的方法
static void Swap (ref int one, ref int two)
{
//形参前ref
//下面的语句,实际上是修改传进来的实参的地址,也称作数据的引用
int temp = one;
one = two;
two = temp;
}
//根据矩形长,宽计算面积和周长
static void CalculateRect(int length,int width,out int area, out int perimeter )
{
area = length * width;
perimeter = 2 * (length + width);
}
}
int num1 = 1, num2=2;
bool r1 = num1 == num2;
int[] arr01 = new int[] {1}, arr02 =new int[] {1};
bool r2 = arr01 == arr02;
bool r3 = arr01[0]==arr02[0];
问? r1 ,r2 ,r3
r1=true 因为比较的是数据,值类型存储的是数据,在栈上
r2=false 因为是引用类型,存储的是数据的引用,数据放在了堆上,声明(也就是引用的声明)是在栈上
r3=true 实际比较的是数据,是存在于堆上的数据
内存上分为 栈和堆(注意背景)
栈存储: 数据和变量的声明(堆上的数据的地址,也可以叫门牌号)
堆存储: 引用类型的数据
另外:为什么数组要new一下呢?而其他数据的命名却不用new 关键字,例如int 等等不用new
如果仅仅是int[] array 并不会在堆上分配内存,只是在栈上开辟空间
如果是 int[] array = new int[] {1};就是在 栈上定义int[]array 里面存储堆上{1}的引用,堆上开辟空间存储{1}
因为string 是引用类型,是为了保证统一性,所以没用new,
引用类型就包括两个部分
C#中,引用类型和值类型有哪些,晚些时候再贴进来。
栈上的内容运行完方法之后就会清理,堆上的内容运行完后,由C#垃圾回收机制自动跟踪
GC线程从栈中的引用开始跟踪,从而判定哪些内存是正在使用的,若GC无法跟踪到某一块堆内存,
那么就认为这块内存不再使用了,即为可回收。