zoukankan      html  css  js  c++  java
  • 引用类型和值类型学习笔记

    一、基本概念

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

                                                             图片1

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

    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

  • 相关阅读:
    Java IO6:字符流进阶及BufferedWriter、BufferedReader
    Java IO5:字符流
    Java IO4:字符编码
    Java IO3:字节流
    Java IO2:RandomAccessFile
    Java IO1:IO和File
    Java异常
    Java语法糖4:内部类
    SharePoint JavaScript API 根据文件路径删除文件
    SharePoint PowerShell 批量删除遗弃视图
  • 原文地址:https://www.cnblogs.com/DuoLaCM/p/5243755.html
Copyright © 2011-2022 走看看