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方法作用范围?
请一条一条解释一下,读不懂,很生硬,,谢谢!!!
{
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方法作用范围?
请一条一条解释一下,读不懂,很生硬,,谢谢!!!
值参数不是还有值类型、引用类型吗(类的引用)?
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方法作用范围?",完全是笔误
不是 是创建后的对象
引用类型创建后会在内存的堆中创建实例或者说对象 在栈上有地址指向这个堆中的对象
比如
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地址是不同的 所以指向的堆中对象也不同 虽然他们的对象中的值是相同的
这个你能理解下来 余下的问题就不必我说了 自己去理解吧
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();
}
另外,11楼朋友,出现d = new Data();为什么0x00A60123就变成0x00A60122了呢?
基础薄弱,对已有答案还不能深入领会一针见血/一劳永逸地办法:
楼主稍稍学习一下汇编吧,看看CPU是如何工作的,重点是理解CPU是如何寻址的(推荐王爽的书)
然后你把桶给了你的朋友Test1,他往桶里又加了90L水并且还给了你,这里你的桶里一共正好100L水。
最后你又把桶给了你的另一个朋友Test2想要把水加到200L,可他却没有往你的桶里加水,而是自己去商店里重新买了一只水桶加上了190L,凑足了200L水之后,又把新买的桶连同水一起扔了(不知道是不是过年吃得太好撑到了),而你给的那只桶仍旧原封不动地还给了你,所以你的桶里还是100L水。
{
d = new Data(); //是不是等同于Data d = new Data;
d.i = 200;
}