• 值类型和引用类型


    用几个案例来解释值类型和引用类型

    首先看值类型,案例如下:

    案例一:

     1 static void Main(string[] args)
     2         {
     3             int n = 10;
     4             M1(n);
     5             Console.WriteLine(n);//10
     6             Console.ReadKey();
     7         }
     8 
     9         private static void M1(int m)
    10         {
    11             m++;
    12         }
    View Code

    解释:第一次声明变量n,会在栈中开辟一块空间,我们自己命名为n,赋值后,空间中就存了10.调用方法的时候,把n传给方法,相当于把n赋值给m,所以m变成10,然后执行方法内部的代码(m++),此时m=11。但是我们要输出的变量是n,所以结果仍然是10.

    案例二:

     1 static void Main(string[] args)
     2         {
     3             #region 案例一
     4             //int n = 10;
     5             //M1(n);
     6             //Console.WriteLine(n);//10
     7             #endregion
     8 
     9             #region 案例一
    10             Person p = new Person();
    11             p.Age = 100;
    12             M2(p);
    13             Console.WriteLine(p.Age);//101
    14             #endregion
    15 
    16             Console.ReadKey();
    17         }
    18 
    19         private static void M2(Person p1)
    20         {
    21             p1.Age++;
    22         }
    View Code

    解释:Person p=new Person();首先在堆中开辟一块空间,保存person对象,给Age赋值为100,这块堆的内存名称为x00x32,保存在栈中,对应的栈名称我们取名为p。当调用M2()方法的时候,我们重新声明了一个变量p1,并且把p赋给p1(变量都是值类型),等效于把栈中的值复制一份存入p1这块栈中,所以p,p1都指向x00x32这块内存,执行方法中的代码后,p.Age,p1.Age都为101。

    案例三:

     1 class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             #region 案例一
     6             //int n = 10;
     7             //M1(n);
     8             //Console.WriteLine(n);//10
     9             #endregion
    10 
    11             #region 案例二
    12             //Person p = new Person();
    13             //p.Age = 100;
    14             //M2(p);
    15             //Console.WriteLine(p.Age);//101
    16             #endregion
    17 
    18             #region 案例三
    19             Person p = new Person();
    20             p.Age = 100;
    21             M3(p);
    22             Console.WriteLine(p.Age);//
    23             #endregion
    24 
    25 
    26             Console.ReadKey();
    27         }
    28 
    29         private static void M3(Person p1)
    30         {
    31             p1.Age = 1000;
    32             p1 = new Person();
    33             p1.Age = 200;
    34         }
    35 
    36         private static void M2(Person p1)
    37         {
    38             p1.Age++;
    39         }
    View Code

    结果为1000.

    案例四:

     1 static void Main(string[] args)
     2         {
     3             #region 案例一
     4             //int n = 10;
     5             //M1(n);
     6             //Console.WriteLine(n);//10
     7             #endregion
     8 
     9             #region 案例二
    10             //Person p = new Person();
    11             //p.Age = 100;
    12             //M2(p);
    13             //Console.WriteLine(p.Age);//101
    14             #endregion
    15 
    16             #region 案例三
    17             //Person p = new Person();
    18             //p.Age = 100;
    19             //M3(p);
    20             //Console.WriteLine(p.Age);//1000
    21             #endregion
    22 
    23             #region 案例四
    24             Person p = new Person();
    25             p.Age = 100;
    26             M4(p);
    27             Console.WriteLine(p.Age);//100
    28             #endregion
    29 
    30             Console.ReadKey();
    31         }
    32 
    33         private static void M4(Person p1)
    34         {
    35             p1 = new Person();
    36             p1.Age++;
    37         }
    View Code

    Person p=new Person();在堆中开辟一块空间x001,Age=100,把堆的名称x001保存到栈中,栈中开辟的空间(实际的名称没显示)我们自己命名为p。调用方法时,又在栈中开辟了一块空间,我们自己命名为p1,然后把p1赋值给p,由于变量名称都是值类型,所以直接把p中x001拷贝一份给p1,这时候p,p1都指向x001这块堆空间。接下来执行方法中的代码的时候,又在堆中开辟了一块空间x002(类成员Age的初始默认值为0,p1.Age++后为1),然后赋值给p1,这时候,p1中保存堆名称变成x002了.但是我们输出的是p.Age,所以仍然是100.

    案例五:

     1      {
     2             #region 案例五
     3             string name = "科比";
     4             M5(name);
     5             Console.WriteLine(name);//科比
     6             #endregion
     7 
     8             Console.ReadKey();
     9         }
    10 
    11         private static void M5(string name1)
    12         {
    13             name1 = "乔丹";
    14         }        
    View Code

    注意:变量都是值类型的,存在栈中 。

    案例六:

     1     {
     2             #region 案例六
     3             int[] arrInt = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 };
     4             M6(arrInt);
     5             //??????????
     6             for (int i = 0; i < arrInt.Length; i++)
     7             {
     8                 Console.WriteLine(arrInt[i]);//1,2,3,4,5,6,7,8
     9             }
    10             #endregion
    11 
    12             Console.ReadKey();
    13         }
    14 
    15         private static void M6(int[] arrInt1)
    16         {
    17             arrInt1 = new int[arrInt1.Length];
    18             for (int i = 0; i < arrInt1.Length; i++)
    19             {
    20                 arrInt1[i] = arrInt1[i] * 2;
    21             }
    22         }        
    View Code

    int[] arrInt = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 };先在堆中开辟一块空间x001,并且初始化数组。栈中开辟的空间保存x001,我们自己把栈中空间命名为arrInt,调用方法的时候,声明了变量arrInt1,在栈中又开辟了一块空间x002,我们命名为arrInt1,然后把arrInt赋值给arrInt1,因为变量都是值类型,所以直接把栈的内容拷贝一份到arrInt1中,此时arrInt,arrInt2都指向x001这块内存。接下来执行方法中的代码。在M6方法中,先在堆中开辟了一块空间x002,指定了数组的长度,但是没有初始化,由于是int类型,所以数组的所有元素都是0,然后把x002保存到栈中,此时arrInt1就不再指向x001,而是指向了x002,最后操作数组arrInt1。我们需要输出的是arrInt,所以最后的值是1,2,3,4,5,6,7,8。

    案例七:

     1 {
     2             #region 案例七
     3             int[] arrInt = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 };
     4             M7(arrInt);
     5             //??????????
     6             for (int i = 0; i < arrInt.Length; i++)
     7             {
     8                 Console.WriteLine(arrInt[i]);
     9             }
    10             #endregion
    11 
    12             Console.ReadKey();
    13         }
    14 
    15         private static void M7(int[] arrInt1)
    16         {
    17             for (int i = 0; i < arrInt1.Length; i++)
    18             {
    19                 arrInt1[i] = 100;
    20             }
    21         }        
    View Code

    接下来我们把上面的方法全部改成引用传递,看看有什么异同。

    案例一:

     1   #region 案例一
     2             int n = 10;
     3             M1(ref n);
     4             Console.WriteLine(n);
     5             #endregion
     6 
     7 private static void M1(ref int m)
     8         {
     9             m++;
    10         }
    View Code

     int n=10;在栈中开辟一块空间x001,存入10,我们给这块空间的名称重新命名为n,值传递会把内存中的东西(不管保存的是内容还是地址)拷贝一份,引用传递传递的是电脑给内存分配的地址x001,所以值传递等效于我们给x001这个地址又重新起了个名字m, m,n都对应x001这个内存名称,x001对应分配的内存,但是m,n都不保存。所以m++后,n也会变。(至于m,n为什么不保存需要研究)。所以最终输出11.

    把代码转换为IL语言后,发现内存中是不存在m,n变量的,只有内存地址,程序是根据内存地址读取数据的。

    所以值传递传递的是栈中内容,对于值类型,栈中的类型就是栈中的数据,对于引用类型,栈中的内容就是对象的地址。引用传递传递的是栈本身的地址,多个变量名实际上指向的是同一个栈变量。

     案例二:

     1             #region 案例二
     2             Person p = new Person();
     3             p.Age = 100;
     4             M2(ref p);
     5             Console.WriteLine(p.Age);//101
     6             #endregion
     7 
     8 private static void M2(ref Person p1)
     9         {
    10             p1.Age++;
    11         }
    View Code

    结果是101;

    案例三:

     1 #region 案例三
     2             Person p = new Person();
     3             p.Age = 100;
     4             M3(ref p);
     5             Console.WriteLine(p.Age);//
     6             #endregion
     7 
     8 private static void M3(ref Person p1)
     9         {
    10             p1.Age = 1000;
    11             p1 = new Person();
    12             p1.Age = 200;
    13         }
    View Code

    Person p=new Person();在堆中开辟一块空间x001,Age=100,保存在栈中,栈这块内存地址是y001,里面保存的内容是x001,我们自己命名为p,调用方法时,采用引用传递,只是给栈的地址换了个别名,改为p1,p,p1还是指向栈中y001这块内存。执行方法后,在堆中重新分配了块内存x002,并且赋值给p1,所以栈中x001这块内存中存的内容变成x002,然后改变Age=200,到这里实际上p,p1都指向了x002这块内存,所以最终的结果为200.

    案例四:

     1  #region 案例四
     2             Person p = new Person();
     3             p.Age = 100;
     4             M4(ref p);
     5             Console.WriteLine(p.Age);//
     6             #endregion
     7 
     8 private static void M4(ref Person p1)
     9         {
    10             p1 = new Person();
    11             p1.Age++;
    12         }
    View Code

    结果:1;

    案例五:

     1 #region 案例五
     2             string name = "科比";
     3             M5(ref name);
     4             Console.WriteLine(name);//
     5             #endregion
     6 
     7 private static void M5(ref string name1)
     8         {
     9             name1 = "乔丹";
    10         }
    View Code

    结果是:乔丹

    案例六:

     1  int[] arrInt = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 };
     2             M6(ref arrInt);
     3             //??????????
     4             for (int i = 0; i < arrInt.Length; i++)
     5             {
     6                 Console.WriteLine(arrInt[i]);//
     7             }
     8 
     9 private static void M6(ref int[] arrInt1)
    10         {
    11             arrInt1 = new int[arrInt1.Length];
    12             for (int i = 0; i < arrInt1.Length; i++)
    13             {
    14                 arrInt1[i] = arrInt1[i] * 2;
    15             }
    16         }
    View Code

    结果全部是0;

    案例七:

     1  #region 案例七
     2             int[] arrInt = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 };
     3             M7(ref arrInt);
     4             //??????????
     5             for (int i = 0; i < arrInt.Length; i++)
     6             {
     7                 Console.WriteLine(arrInt[i]);
     8             }
     9             #endregion
    10 
    11  private static void M7(ref int[] arrInt1)
    12         {
    13             for (int i = 0; i < arrInt1.Length; i++)
    14             {
    15                 arrInt1[i] = 100;
    16             }
    17         }
    View Code

    全部是100

  • 相关阅读:
    C++: string的大小写转换
    c++自由的转换string和number
    C# 中的数据库操作~存储过程篇Mysql SqlServer
    Google Protocol Buffer Basics: C++
    C#中的扩展方法(向已有类添加方法,但无需创建新的派生类型)
    多态以及虚析构函数的使用
    【Java基础】String 相关知识点总结
    【设计模式】抽象工厂模式
    【设计模式】工厂方法模式
    【设计模式】简单工厂
  • 原文地址:https://www.cnblogs.com/wesley168/p/6406473.html
Copyright © 2020-2023  润新知