引用类型和值类型学习笔记

时间:2022-09-24 15:45:12

一、基本概念

      CLR支持两种类型,值类型和引用类型。它们从类型的定义、实例的创建、参数传递、到内存的分配都有所不同;.NET中的类型分类如下:

                                                         引用类型和值类型学习笔记

值类型和引用类型最本质的区别在于内存的分布上,大致可以这么说---->:值类型存在栈上,引用类型存在堆上;

1、什么是堆和栈?

      栈(stack):栈是基于线程的,一个线程会包含一个线程栈。线程中的值类型在对象作用域结束的时候会自动被清理;栈是由操作系统负责管理的,用于存放值类型变量和引用类型在托管堆上的地址;

      托管堆(GC Heap):进程在初始化的时候在进程地址空间上划分内存,存储.NET运行过程中的对象,所有的引用类型都存储在托管堆上,托管堆上分配的对象是由GC负责管理和释放的;托管堆是基于进程的;

二、值类型一直都存在栈上吗,引用类型一直都存在堆上吗?

1.单独的值类型变量,如局部值类型变量都是存储在栈上面的;

2.当值类型是自定义class的一个字段、属性时,它随引用类型存储在托管堆上,此时她是引用类型的一部分;

4.所有的引用类型肯定都是存放在托管堆上的。

5.结构体(值类型)中定义引用类型字段,结构体是存储在栈上,其引用变量字段只存储内存地址,指向堆中的引用实例。

三、值类型和引用类型的参数传递

       值类型变量在传递给另外一个变量时,会执行一次复制,复制的是值;

       引用类型在传递给另一个变量时,也会执行一次复制,但复制的却是引用对象的地址;

            int v1 = 0;
            int v2 = v1;
            v2 = 100;
            Console.WriteLine("v1=" + v1); //输出:v1=0
            Console.WriteLine("v2=" + v2); //输出:v2=100

            User u1=new User();
            u1.Age = 0;
            User u2 = u1;
            u2.Age = 100;
            Console.WriteLine("u1.Age=" + u1.Age); //输出:u1.Age=100
            Console.WriteLine("u2.Age=" + u2.Age); //输出:u2.Age=100,因为u1/u2指向同一个对象

当把对象作为参数传递的时候,效果同上面一样,他们都称为按值传递;

 

四、引用传递:

     按引用传递的两个主要关键字:outref不管值类型还是引用类型,按引用传递的效果是一样的,都不传递值副本,而是引用的引用(类似c++的指针的指针)

     outref告诉编译器方法传递额是参数地址,而不是参数本身;

private void DoTest( ref int a)
        {
            a *= 2;
        }

        private void DoUserTest(ref User user)
        {
            user.Age *= 2;
        }

        [NUnit.Framework.Test]
        public void DoParaTest()
        {
            int a = 10;
            DoTest(ref a);
            Console.WriteLine("a=" + a); //输出:a=20 ,a的值改变了
            User user = new User();
            user.Age = 10;
            DoUserTest(ref user);
            Console.WriteLine("user.Age=" + user.Age); //输出:user.Age=20
        }

outref的主要异同

  • outref都指示编译器传递参数地址,在行为上是相同的;
  • 他们的使用机制稍有不同,ref要求参数在使用之前要显式初始化,out要在方法内部初始化;
  • outref不可以重载,就是不能定义Method(ref int a)和Method(out int a)这样的重载,从编译角度看,二者的实质是相同的,只是使用时有区别;

 

摘抄自:http://www.cnblogs.com/anding/p/5229756.html