zoukankan      html  css  js  c++  java
  • C# List 作为参数传递的值变化

    一、示例演示

    namespace TestConsole
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("");
    
                List<string> list1 = new List<string>();
                Test1(list1);
                Console.WriteLine(" list1:" + list1.Count()); // 总数量为 1
    
                Console.WriteLine("");
                Console.WriteLine("---- 亮瞎眼的分割线 ----"); 
                Console.WriteLine(""); 
    
                List<string> list2 = new List<string>();
                Test2(list2);
                Console.WriteLine(" list2:" + list2.Count()); // 总数量仍为 0
    
                Console.WriteLine("");
            }
    
            static void Test1(List<string> list)
            {
                list.Add("1");
                Console.WriteLine(" Test1():" + list.Count()); // 总数量为 1
            }
    
            static void Test2(List<string> list)
            {
                List<string> list2 = new List<string>();
                list2.Add("1");
    
                list = list2;
                Console.WriteLine(" Test2():" + list.Count()); // 总数量为 1
            }
        }

    可以发现:

    经过 Test1后,list 的元素数量由 0 变为 1 了,

    经过 Test2后,list 的元素数量还是0。

    二、解说

    1.list类型是引用类型

    2.引用本身是类似于一个“保存地址的值变量”
    所以从方法外部传入引用到方法里,那么其实引用本身是复制了一份副本来给方法里使用的,只是说这个复制的引用副本和之前的引用的内容(也就是所指向的对象内存地址)是一样的,所以通过引用操作对象的数据时,可以看到2个引用都操作的同一个对象;但如果你是修改了引用副本本身的值内容(将该引用指向了一个新的对象的内存地址),那么是不会影响到之前方法外的那个引用的,所以修改后会发现2个引用所指向的对象不同了

    而如果对象引用参数前加上了ref,那么方法参数所传递的不再是引用的副本,而是引用的地址了(即通过引用的地址找到引用,再读出引用里保存的内存地址值,再根据则个地址值去找到真正要操作的对象),所以如果此时你再修改这个引用的值时,会根据引用的地址找到方法外的那个引用,然后修改其内容,所以会发现方法外的引用也会指向新的对象了

    3这里有三段代码

    你可以看看,体会一下:

    (1)

    List<string> list=new List<string>();
    ModifyList(list);
    Console.WriteLine(list.Count)
     
    private void ModifyList(List<string> list)
    {
       // 这里的list其实已经是一个引用副本了,但是所指向的内存地址仍然是原本方法外面的对象的,所以后面用该引用的Add方法所操作的,仍然是原本方法外面的对象的内存数据
        list.Add("1");
        list.Add("2");
        list.Add("3");
    }

    (2)

    List<string> list=new List<string>();
    ModifyList(list);
    Console.WriteLine(list.Count)
     
    private void ModifyList(List<string> list)
    {
        list = new List<string>(); // 这里其实已经将引用指向了新的内存地址,所以后续的Add操作是在操作新对象的内存数据,而原来方法外的对象其实是没有受到影响的
        list.Add("1");
        list.Add("2");
        list.Add("3");
    }

    (3)

    List<string> list=new List<string>();
    List<string> copy = list; // 复制一个引用
    ModifyList(ref list);
    Console.WriteLine(copy.Count) // 复制的这个引用仍然指向原来最早的那个List
    Console.WriteLine(list.Count) // list这个引用已经在ModifyList方法里被修改了,指向的是在ModifyList方法里新new出来的对象了
     
    private void ModifyList(ref List<string> list)
    {
        list = new List<string>(); // 因为有ref,所以这里其实已经将方法外原本的那个引用也指向了新的内存地址,所以后续的Add操作是在操作新对象的内存数据,并且方法外原本的那个引用也指向了这个新的对象
        list.Add("1");
        list.Add("2");
        list.Add("3");
    }

    参考:

    http://www.cftea.com/c/2013/01/5724.asp

    http://bbs.csdn.net/topics/390600826

  • 相关阅读:
    Collections.unmodifiableMap,Collections.unmodifiableList,Collections.unmodifiableSet作用及源码解析
    Mybatis源码解析,一步一步从浅入深(五):mapper节点的解析
    Mybatis源码解析,一步一步从浅入深(四):将configuration.xml的解析到Configuration对象实例
    Mybatis源码解析,一步一步从浅入深(三):实例化xml配置解析器(XMLConfigBuilder)
    Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码
    Cannot find class: com.mysql.jdbc.Driver错误及解决办法。
    Mybatis源码解析,一步一步从浅入深(一):创建准备工程
    Maven 创建项目之简单示例
    常用注解记录
    jmeter性能测试工具
  • 原文地址:https://www.cnblogs.com/xcsn/p/7345165.html
Copyright © 2011-2022 走看看