public class Data
    {
        public int i = 10;
    }
    public class Class1
    {
        public static void Test1(Data d)
        {
            // 参数d只是一个引用副本,和原引用变量d同时指向同一个对象,因此都可以修改该对象的状态。
            d.i = 100;
        }
        public static void Test2(Data d)
        {
            // 创建新的Data对象,并将参数d指向它。此时参数d和原有引用d分别指向2个不同的Data对象,因此
            // 当超出Test方法作用范围时,参数d和其引用的对象将失去引用,等待GC回收。
            d = new Data();
            d.i = 200;
        }
      
        public static void Main(string[] args)
        {
            Data d = new Data();
            Console.WriteLine(d.i); // 10
            Test1(d);
            Console.WriteLine(d.i); // 100
            Test2(d);
            Console.WriteLine(d.i); // 100
            Console.ReadKey();
        }
    } 上述代码请  不  要  讲ref、out...........请问:
Test1:
参数d只是一个引用副本,和原引用变量d同时指向同一个对象,因此都可以修改该对象的状态。
同时指向一个对象?谁?这个对象是谁?Test2:
创建新的Data对象,并将参数d指向它。此时参数d和原有引用d分别指向2个不同的Data对象,因此 当超出Test方法作用范围时,参数d和其引用的对象将失去引用,等待GC回收。请解剖一下这句话:
1:创建新的Data对象.....这里的对象是谁?是不是d ?
2:此时参数d和原有引用d...?到底谁是谁?参数d是不是(Data d)这个d,原有引用d是不是Test2(d)这个d?
3:此时参数d和原有引用d分别指向2个不同的Data对象....对象到底是谁?
4:当超出Test方法作用范围时,参数d和其引用的对象将失去引用,等待GC回收......Test2(d)调用了Test2方法,怎么说超出Test方法作用范围?
请一条一条解释一下,读不懂,很生硬,,谢谢!!!

解决方案 »

  1.   

    其实,我只想了解值参数,引用参数(ref、out)不用说
    值参数不是还有值类型、引用类型吗(类的引用)?
      

  2.   

    首先解释一下参数副本的意义:
    public static void Test1(Data d)
      {
        d.i = 100;
      }
    变成机器码操作时是这样:
    public static void Test1(Data d)
      {
        Data d2 = d;
        d2.i = 100;//d2出了函数就结束了生命期,但它的修改反映到了d中
      }
    看出没?会先复制参数的副本
    由于Data是引用类型,虽然d和d2处于内存中不同的位置,是两个独立的变量,但d和d2指向同一个对象,也就是说,d和d2这两块内存的内容是一样的,都是一个Data对象的地址有了上面的知识,再分析另一个函数:
    public static void Test2(Data d)
      {
        d = new Data();
        d.i = 200;
      }
    动态生成机器码执行时类似这样:
    public static void Test2(Data d)
      {
        Data d2 = d;//此时d和d2虽然不同,但它们的内容一样,都指向同一个Data对象
        d2 = new Data();//此时d2的内容变化了,指向new出来的新Data对象,而参数d不变
        d2.i = 200;//修改的是新Data对象,并未反应到参数d对象中
      }//此时,d2对象具备回收条件,生命周期结束理解了上面的内容,你的所有问题迎刃而解至于"Test2(d)调用了Test2方法,怎么说超出Test方法作用范围?",完全是笔误
      

  3.   

    不要套用c的指针操作概念。因为.net的对象引用不是内存地址概念,而是一个对内存地址的非常高级的动态包装后了的对象,它顶多是一个对象的内部ID号,而不是一个所谓内存地址。所谓代码 Data d2 = d; 并不是说把的“d这块内存”的内容拷贝给“d2这块内存”。顶多可以看作把d这个变量所代表的对象的唯一编号赋值给d2这个变量,于是这两个变量(这两个对象引用)都有着相同的唯一id号。如果你动不动套用c、c++的所谓“这两块内存”,脑子就乱了。
      

  4.   

    因为Data是类  类是引用类型 执行Text1 传递的是对象是在Text1方法里发生改变 所以执行出来的结果是100 而Text2其实并没有发生改变 只是指向了一个新的所以还是100 
      

  5.   

    1:创建新的Data对象.....这里的对象是谁?是不是d ?
    不是  是创建后的对象
    引用类型创建后会在内存的堆中创建实例或者说对象  在栈上有地址指向这个堆中的对象
    比如
    Test t1 = new Test();
    来看下表
    对象       堆栈                       堆
    t1         0x00A60123(存放地址)    0066002000(值)  再看下面操作
    Test t2;
    Test t1 = t2;
    对象       堆栈                       堆
    t1        0x00A60123             0066002000
    t2        0x00A60123(复制的是t1的地址)
    t1=t2 地址相同 那么堆中的对象当然也是相同 也就是指向同一对象 就是t1t2都指向0066002000
    如果堆中的值变了  当然t1t2都会变了那么如果接下来
    t1 = new Test();
    对象       堆栈                       堆
    t1        0x00A60123(存放地址)    0066002000
    t1        0x00A63322             0066002000
    这2个t1地址是不同的  所以指向的堆中对象也不同  虽然他们的对象中的值是相同的
    这个你能理解下来  余下的问题就不必我说了  自己去理解吧
      

  6.   


    public static void Main(string[] args)
      {
      //new一个对象,Data对象在 托管椎中分配一块内存(如a),在 栈中声明了一个变量d,指向这个椎中a对象
      Data d = new Data();
      Console.WriteLine(d.i); // 10
     /* 引用类型,传递的是引用地址,不是椎中对象a的副本,而是栈中d的副本,
        而d的副本又指向对象a,既操作了对象a*/
      Test1(d);
      Console.WriteLine(d.i); // 100
     /* 引用类型,传递的是引用地址,不是椎中对象a的副本,而是栈中d的副本,
        而d的副本又指向对象a,既操作了对象a,但是 你new了一个新对象,既d的副本不再指向对象a,而是指   向new出来的另一个对象,跟a对象 没有关系了*/
      Test2(d);
      Console.WriteLine(d.i); // 100
      Console.ReadKey();
      }
      

  7.   

    我想再问一下:d = new Data();是不是等同于Data d = new Data;也就是传说中的创建对象...是不是?
    另外,11楼朋友,出现d = new Data();为什么0x00A60123就变成0x00A60122了呢?
      

  8.   


    基础薄弱,对已有答案还不能深入领会一针见血/一劳永逸地办法:
    楼主稍稍学习一下汇编吧,看看CPU是如何工作的,重点是理解CPU是如何寻址的(推荐王爽的书)
      

  9.   

    打个比方你去商店里买了一只水桶,因为商店搞活动,每只桶送10L水,所以拿到水桶以后里面有10L水。
    然后你把桶给了你的朋友Test1,他往桶里又加了90L水并且还给了你,这里你的桶里一共正好100L水。
    最后你又把桶给了你的另一个朋友Test2想要把水加到200L,可他却没有往你的桶里加水,而是自己去商店里重新买了一只水桶加上了190L,凑足了200L水之后,又把新买的桶连同水一起扔了(不知道是不是过年吃得太好撑到了),而你给的那只桶仍旧原封不动地还给了你,所以你的桶里还是100L水。
      

  10.   

    public static void Test2(Data d)
      {
      d = new Data();   //是不是等同于Data d = new Data;
      d.i = 200;
      }