zoukankan      html  css  js  c++  java
  • 详解值类型与引用类型 结合ref (利用案例一步步分析内存的变化)

    储存数组其实不是对象,而是对象的引用地址(储存对象的计算机的内存地址)
    值类型,当方法调用的时候,因为传递进 方法的值只是原变量的一个副本,所以改变了副本不会改变原变量。
    引用类型,当方法调用的时候,因为传递进方法的也是一个副本,只不过是 引用的副本,这个引用的副本也是指向 原对象的,所以修改了引用副本就会影响到对象。

    如果结合这个案例,彻底把这个过程分析清楚:
    分析案例:

    class Program
    {
    static void Main(string[] args)
    {
    int[] ints = { 1, 2, 3 };
    int[] intsCopy = ints;//复制数组,使变量引用内存中相同的数组对象
    Change(ints);//调用方法,传入引用
    //ints :2 4 6
    //intsCopy:2 4 6
    int[] ints_second = { 1, 2, 3 };
    int[] ints_secondCopy = ints_second;
    ChangeAndRef(ref ints_second);//注意ref传入方法的引用是哪一个,那么 该引用就指向方法体内的新对象。


    //ints_second:11 12 13
    //ints_secondCopy:2 4 6
    }
    static void Change(int[] array)
    {
    for (int i = 0; i < array.Length; i++)
    {
    array[i] *= 2;
    }
    array = new int[] { 11, 12, 13 };
    }
    static void ChangeAndRef(ref int[] array)
    {
    for (int i = 0; i < array.Length; i++)
    {
    array[i] *= 2;
    }
    array = new int[] { 11, 12, 13 };
    }


    第一步:int[] ints;这个是声明一个引用变量,这个时候不开辟内存
    第二步:给数组初始化或者赋值,就会开辟内存,这里的开辟内存是值 用引用变量---指向--内存的地址--这个地址上有 一个对象(对象是占用内存的)
    第三步:int[] intsCopy=ints;这是 声明一个 引用变量,让这个变量也---指向--内存中的地址---对象
    第四步:调用方法,这个时候注意了,引用类型是把引用变量的副本信息,传递进方法里,这个引用变量的副本---对应---对象
    第五步:因为引用副本所对应的地址也是内存中的对象,所以会修改对象,因此 原引用变量---对应内存中地址的对象(改变)
    第六步:因为在方法体内 new 了一个新对象,就是开辟了一个新内存,那么方法体的引用变量是可以 指向这块内存的地址的,但是方法体外部的引用对象是无法指向这个方法体内的对象的,所以我们看到 方法1新 new int[] 未能改变引用变量--对应的对象

    核心:

    第二个方法体:利用ref 使得 引用了引用变量,也就是说修改了引用变量指向的对象。所以array=new int[],改变了原来的ints_second的引用--对象,但是并未修改ints_secondCopy的引用变量---所对应的对象。这个方法体:1.改变了原Ints_second的对象  2.在方法体内new一块新内存,让ints_second 指向了这块新内存上的对象

    值类型:
    案例1:(void情况)

    class Program
    {
    static void Main(string[] args)
    {
    int i = 5;//这里是Int类型所以是值类型
    Console.WriteLine("The current i is {0}",i);//5

    Change(i);
    Console.WriteLine("The now i is {0}",i);//5 ,这里可以看出值类型不会改变原变量的值
    }


    static void Change(int i)
    {
    i *= 2;
    Console.WriteLine("The i is {0}",i);//10
    }
    }


     如果使用ref参数的话,那么方法体传递的就是对i的引用,那么就是会修改原i所对应的值的。


    案例2:(有返回值的情况)

     class Program
    {
    static void Main(string[] args)
    {
    int i = 5;//这里是Int类型所以是值类型
    Console.WriteLine("The current i is {0}", i);//5

    int new_i=Change(i);
    Console.WriteLine("The now i is {0}", i);//5 ,这里可以看出值类型不会改变原变量的值
    Console.WriteLine("The new_i is {0}",new_i);//10,这里可以看出值类型的是把副本的值改变了,其实并没有改变原变量的值
    }
    static int Change(int i)
    {
    i *= 2;
    Console.WriteLine("The i is {0}", i);//10
    return i;
    }
    }

    引用类型:
    案例3:(void情况)

    class Program
    {
    static void Main(string[] args)
    {
    int[] ints = { 1, 2, 3, 4, 5 };
    Console.WriteLine("Lengths is {0}", ints.Length);//5
    Console.WriteLine("The current ints is:");
    foreach (int i in ints)
    {
    Console.Write(i + ""); // 1 2 3 4 5
    }

    int[] intsCopy = ints;//复制一份给intsCopy

    Console.WriteLine();
    ChangeArray(ints);
    Console.WriteLine("The Now ints is:"); // 2 4 6 8 10,这里不一样了,变量引用的对象改变了!!
    foreach (int i in ints)
    {
    Console.Write(i + "");
    }

    Console.WriteLine("The Now intsCopy is :");
    foreach (int i in intsCopy)
    {
    Console.Write(i + "");//2 4 6 8 10 ,注意!!这里是原变量的复制版本居然也改变了,说明引用类型被方法调用修改是修改原变量的。
    }
    }
    static void ChangeArray(int[] array)
    {
    for (int i = 0; i < array.Length; i++)
    {
    array[i] = array[i] * 2;
    }
    }
    }

    案例4:(有返回值)

    class Program
    {
    static void Main(string[] args)
    {
    int[] ints = { 1, 2, 3, 4, 5 };
    Console.WriteLine("Lengths is {0}", ints.Length);//5
    Console.WriteLine("The current ints is:");
    foreach (int i in ints)
    {
    Console.Write(i + ""); // 1 2 3 4 5
    }
    Console.WriteLine();
    int[] intsCopy = ints;//复制一份给intsCopy
    int[] new_ints = ChangeArray(ints);
    Console.WriteLine("The new_ints is:");
    foreach (int i in new_ints)
    {
    Console.Write(i + "");//2 4 6 8 10
    }
    Console.WriteLine();
    ChangeArray(ints);
    Console.WriteLine("The Now ints is:"); // 4 8 12 16 20
    foreach (int i in ints)
    {
    Console.Write(i + "");
    }
    Console.WriteLine();
    Console.WriteLine("The Now intsCopy is :");
    foreach (int i in intsCopy)
    {
    Console.Write(i + "");//4 8 12 16 20
    }

    }
    static int[] ChangeArray(int[] array)//定义方法修改数组
    {
    for (int i = 0; i < array.Length; i++)
    {
    array[i] = array[i] * 2;
    }
    return array;
    }
    }

    运行结果:
    Lengths is 5
    The current ints is:
    1 2 3 4 5
    The new_ints is:
    2 4 6 8 10
    The Now ints is:
    4 8 12 16 20
    The Now intsCopy is :
    4 8 12 16 20


     

  • 相关阅读:
    FckEditor添加右键菜单;增加编辑区右键图片删除功能(asp.net )(二)
    GridView空数据时显示表头
    FckEditor添加右键菜单;增加编辑区右键图片删除功能(asp.net )(一)
    《InsideUE4》6GamePlay架构(五)Controller
    《Inside UE4》1基础概念
    《Inside UE4》2GamePlay架构(一)Actor和Component
    《InsideUE4》7GamePlay架构(六)PlayerController和AIController
    《InsideUE4》3GamePlay架构(二)Level和World
    Medusa引擎开源了
    《Inside UE4》0开篇
  • 原文地址:https://www.cnblogs.com/IAmBetter/p/2289584.html
Copyright © 2011-2022 走看看