咱们可能见到下面的代码ui
public static void StringBuilderNoRef(StringBuilder s) {指针
s.Append(" World");对象
s = new StringBuilder("hi");blog
}内存
public static void StringBuilderRef(ref StringBuilder s) {变量
s.Append(" World");引用
s = new StringBuilder("hi");方法
}im
当咱们先建立一个实例 StringBuilder s = new StringBuilder("Hello");static
把s做为参数分别传递到两个方法的时候,咱们会发现
输出结果是不同的,一个是 Hello World,另外一个是 hi
缘由其实就是 在调用第一个方法的时候,传递了这个引用类型对象的引用的副本(不是对象自己),因此对于在调用方法外部的引用和方法中的引用来讲,这两个引用都指向堆上的同一个对象。因此在修改此对象的属性值时,修改同时会应用于内部和外部的两个引用上。但从新分配其引用位置时,则只是修改副本引用的引用位置,原引用(方法外部)的位置不变,原引用仍是指向原来的对象。
而若是加上Ref关键字,这时传入的参数则为些引用对象的原始引用,而不是引用的副本,这样的话,你就不但能够修改原始引用对象的内容,还能够再分配此引用的引用位置(用New 来从新初始化)。
若是你只想在方法中改变引用参数的内容,没有必要使用Ref来修饰引用参数。
若是你但愿在方法中改变引用对象参数的引用(调用方法外的),如从新初始化对象,则须要使用Ref关键字来修饰参数。
下面咱们再结合下图,阐述一下我理解的 实例 引用 对象 副本的区别和联系
如图,new Person()是真正的对象是在堆内存里面,上图一共有3次new Person(),因此会在堆里面开辟3个空间,产生3个实例对象,每一个对象之间都是相互独立的,使用本身的空间。而new Person()就是一个实例化的过程,将类Person生产出不一样的对象。
而等号的左边$p1是一个引用变量,经过赋值运算符“=”把对象的首地址赋给“$p1“这个引用变量,
因此$p1是存储对象首地址的变量,$p1放在栈内存里边,$p1至关于一个指针指向堆里面的对象, 因此咱们能够经过$p1这个引用变量来操做对象,
一般咱们也称对象引用为对象。
其实一个对象就是一个实例,而引用是指一个存放对应首地址的对象,经过$p1这个引用变量来操做对象。
副本则是拷贝了该引用的指针。