4.值传递和引用传递

引用传递和值传递

 

一、值类型和引用类型分类

值类型:int ,double,char,decimal,bool,enum,struct类型都是值类型。 
引用类型:string ,数组,自定义类,集合dictionary、,object、委托,接口都是引用类型。

二、两者在内存的区别:

值类型存在堆上,引用类型存在栈上。

三、值传递和引用传递。

static void Main(string[] args)

        {

            int n1 = 10;

            int n2 = n1;

            n2 = 20;

            Console.WriteLine(n1);

            Console.WriteLine(n2);

            Console.ReadKey();

        }

不难得到结论,输出是: 
10

20
备注:值类型传递的时候,传的是他的本身。 
(把n1的值复制了一下给了n2,当执行“n2 = 20”的时候,把20赋值给了n2。) 
下图是原理的解释,这个应该不难: 

好的,我们看引用类型传递(自定义类)

class Program

    {

        static void Main(string[] args)

        {

            Person p1 = new Person();

            p1.Name = "张三";

            Person p2 = p1;

            p2.Name = "李四";

 

            Console.WriteLine(p1.Name);

            Console.WriteLine(p2.Name);

            Console.ReadKey();

        }

    }

 

    public class Person

    {

        private string _name;

 

        public string Name

        {

            get { return _name; }

            set { _name = value; }

        }

    }

  • 25

结果却是:

李四

李四

 
按照一开始的想法,应该是 张三、李四才对,那么这就是引用类型的传递。我们逐步解释。 
备注:引用类型在复制的时候,传递的是对这个对象的引用或者地址。 
引用类型复制的时候,既然复制的是对象的引用或者地址,那么一开始实例化的一个p1,他在栈上的地址比如说100001,指向堆上的 new Person(),然后实例化了一个p2,把p1复制给了p2,我们说引用类型复制的时候,复制的是对象的引用或者地址,那么p2和p1在栈上的地址是一样的,(但还是开辟了两个栈地址),他们两个都是指向堆的同一个空间。 
所以p1和p2只要有一个改变,那么他们两个都会随之改变!

例子:

class Program

    {

        static void Main(string[] args)

        {

            Person p = new Person();

            p.Name = "张三";

            Test(p);

            Console.WriteLine(p.Name);

            Console.ReadKey();

        }

        public static void Test(Person pp)

        {

            Person p = pp;

            p.Name = "李四";

        }

    }

输出的 是 李四

特殊点:引用类型中的 String

static void Main(string[] args)

        {

            string s1 = "张三";

            string s2 = s1;

            s2 = "李四";

            Console.WriteLine(s1);

            Console.WriteLine(s2);

            Console.ReadKey();

        }

这个按照上面的介绍,引用类型传递的时候,两个之中的任意一个改变,那么就会全部改变,但是,输出却是  张三   李四 

这是因为字符串的不可变性!String就是引用类型之中的特例,面试的时候很多面试官会挖坑让你跳。

四、当用方法进行值传递时:

值传递:当数据做为基础类型和String  在进行传递的时候,其本身的值是不会发生变化的。形参在这里只是接受这个值一份拷贝而已

//测试

public class People {

public int age;

public int changAge(int age) {
age++;
return age;
}
public static void main(String[] args) {
People p = new People();
int age = 20; 
p.changAge(age);
System.out.println(age);
}

}

//结果

20

引用传递: 当数据作为自定义对象在进行传递,整个对象不会进行拷贝,直接由形参所接受,如果有方法操作了这个对象,理所应当的对象就会发生变化

//测试

public class People {

public int age;


public int changeAge(People p) {
int age = p.age++;
return age;
}

public static void main(String[] args) {
People p = new People();
p.age = 20;
p.changeAge(p);
System.out.println(p.age);
}
}

//结果

21

 

五、ref和out的区别

1. ref:
int i =0;
有函数fun(ref i)和fun(i)
它们的函数体都是{ i = 3;},那么在执行以下两段代码后:
(1)fun(i); System.Console.WriteLine(i.ToString());
(2)fun(ref i); System.Console.WriteLine(i.ToString());
(1)的输出是1,(2)的输出是3,

2. out:
int i; //注意,这样个里就是声明了变量i,并木有对其初始化
有函数fun(ref i)、fun(out i)和fun(i)
它们的函数体都是{ i = 3;},那么在执行以下三段代码后:
(1)fun(i); System.Console.WriteLine(i.ToString());
(2)fun(ref i); System.Console.WriteLine(i.ToString());
(3)fun(out i); System.Console.WriteLine(i.ToString());
(1)和(2)在编译的时候都会报错:不准确 CS0165: 用了未赋值的局部变量“i”
而(3)能正常编译,而且输出3

最后总结一次:
Ref和Out这样个2个关键字都能够提供相似的功效,其作用也很像C中的指针变量。稍有不相同之处是:
用Ref型参数时,传入的参数必须先被初始化。而Out则不要要,对Out而言,就必须在方法中对其完成初始化。
用Ref和Out时都必须注意,在方法的参数和执行方法时,都要加Ref或Out关键字。以满足匹配。
Out更适合用在要要Return多个返回值的地方,而Ref则用在要要被调出使用的方法修改调出使用者的引用的时候。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值