一直在博客园怼人,非常惭愧。所以郑重决定:

好好写一篇干货,然后再接着怼人。

这是一起帮上陈百万同学的求助,讲了一会之后,我觉得很有些普世价值,干脆就发到园子来。面向小白,高手轻拍。

我们从最简单的说起(基础知识,懂的同学直接往下拉),直接上代码:

        static int amount;static void AddTV(int amount){amount++;Console.WriteLine("方法中,amount="+amount);}

然后,我们将参数amout传入AddTV()方法,希望能让其+1

            amount = 10;AddTV(amount);Console.WriteLine("AddTV(amount)执行之后,amount=" + amount);

那么执行的结果呢?

amount的数量并没有发生变化。

为什么没有变呢?

这是最入门的知识,通常的解释是:

amount是int类型,int是值类型,所以当它作为参数时,传递给方法的是它的一个副本(复制品),因此方法中改变的是它的副本的值,amount本身并没有改变。

OK,这完全没有问题。而且,如果想改变的值,就需要加 ref 关键字,如下所示:

        static void AddTV(ref int amount){amount++;Console.WriteLine("方法中,amount="+amount);}

大家自己跑一下,看看结果有什么不一样。

这叫做参数的引用传递。

这是最基础的知识,非常清晰。好的,接着,C#是面向对象的语言嘛,我们要引入一个对象。

    public class House{public int TVAmount { get; set; }}

然后,我们把House对象作为参数传递,值传递,不带ref的。如下所示:

        static void AddTV(House house){house.TVAmount++;Console.WriteLine("方法中,house.TVAmount=" + house.TVAmount);}House house = new House();AddTV(house);Console.WriteLine("AddTV(house)执行之后,house.TVAmount=" + house.TVAmount);

执行之后你会发现:

咦?house.TVAmount的值变了耶!

为什么呢?

有的同学听到的解释是这样的:

House是对象,是引用类型,引用类型作为参数传递到方法中,它的值会被方法改变。

有些同学,哦!记住了:值类型传进去不变,引用类型传进去要变,但值类型引用传递又要变……虽然有点绕,但死背下来也行。

但有的同学就开始开始抛问题了:(这种同学特别值得表扬!安利一篇我的文章:讲课这些天(五)怎么才能把代码写好?)

值类型的引用传递,和引用类型的值传递,效果都一样,那他们有什么区别呢?

Good question!

实际上,死背上面的,是会出问题的,我还是用代码展示一下:

        static void AddTV(House house){house = new House();house.TVAmount++;Console.WriteLine("方法中,house.TVAmount=" + house.TVAmount);}

这样写,眼尖的同学一眼就能看出差别:这一次方法体内多了一个:house = new House();

不要以为这是抽风啊,实际的开发代码中,各种各样的原因,很多时候都确实会在方法体内重新new一个参数实例的。

那运行结果怎么样的呢?

怎么样?!引用类型也不好使了?现在,是不是

不像JavaScript到处都是bug和设计缺陷(是的,日常黑js一百年,),C#是一门严谨清晰的语言,不会有什么“灵异”事件。现象和你的想法不一致,一定是你的想法出了问题。

所以,要真正地弄明白这里面的道道,我们还是要回到原点:

首先的首先,看看这代码,你真的明白是什么意思么:

            House house = new House();

我为什么要写成三行?

因为这其实是三个过程:

  • House house 这是声明了一个变量
  • new House() 这是生成了一个对象
  • = 把 house 和 new House() 关联起来

注意,注意我用的是“关联”,很多人喜欢说“赋值”,甚至“等于”,这就容易造成我们理解上的误区。

为了理解这种关联,我画了一幅图:

观察这幅图,house和New House,是不同的数据储存。事实上,在house里面,有一个记录了new Houuse()存储位置的“引用”(reference,这个英文单词有助于我们理解)。所以,当我们house.TVAmount的时候,是通过house找到new House(),然后得到new House()的数据进行操作。

不知道大家能不能明白这一点?

作为对比,我们来看看值类型是怎么样子的。

整个这一块都是int i,int i 里面就直接的存储了10这个数据,没有引用,int i里直接存放数值10,所以叫做“值类型”。

好了,理解了上面的概念之后,我们回头来看方法参数。

C#的说法非常的清晰,只看有没有 ref 关键字:

  1. 不带ref的,一定是“值传递”
  2. 带ref的,一定是“引用传递”

和传递的是什么类型的参数,半毛钱关系没有。

关键是,你要知道:当参数为引用类型时,传递的不是对象(new House()),而是对象的引用(house)

所以,

  • 如果是值传递,传递的是 对象引用的 副本
  • 如果是引用传递,传递的是 对象引用 本身

什么叫做对象引用的副本呢?还是给一幅图:

明白了吧?作为参数的house的副本,还是指向的New House对象,所以,在方法体中使用:house.TVAmount++,最终修改的还是原来的new House()里面的值。

但是,当你在方法体中:house = new House(); 你实际上就干了件啥事呢?

然后,你再:house.TVAmount++,改变的是新的House对象的值啊!(请结合英文单词 new 来理解这一点)

所以,原来的 house 引用指向的对象,就根本没有发生改变。

希望你仍然还保持着清醒的头脑,没有被我弄晕,O(∩_∩)O~

这样我们就可以接着往下走。那假如我们既要保留方法体内的:house = new House(); 又要通过方法,改变传入对象的值,我应该怎么办呢?

……

干脆留作思考题吧? o( ̄┰ ̄*)ゞ

请同学们在理解原理的基础上自己去写一写,跑一跑,仔细的体会体会。

最后,为了更清晰直观的看到所谓“对象的引用”的变化,我给大家一个神器:在调试时使用一元运算符 & 来查看变量的内存地址:

好了,自己折腾去吧!

enjoy it。

周末发帖,送给爱学习的同学们!

+++++++++++++++++++++++++++++++

最后,悄悄的说一句:我们的 一起帮 有了好多新功能,不想去看一看?

转载于:https://www.cnblogs.com/freeflying/p/8005959.html

【基础中的基础】引用类型和值类型,以及引用传递和值传递相关推荐

  1. SQL数据库基础中的基础

    SQL数据库基础中的基础 1.数据库操作 0.0 提前准备 再开始操作之前,需要有数据库,如果没有安装的可以看我上一篇的内容.以下所有操作均在数据库上操作. 1.1 DDL操作 1.1.1 数据库操作 ...

  2. 先来先服务算法代码_程序员算法与数据结构基础中的基础,栈与递归

    在此之前,我们介绍了动态规划.深度优先搜索等基础算法,但是,有部分好友评论说,难度太难了,我们知道动态规划的自顶向下跟深度优先搜索一般都用递归实现,今天我们就先来讲讲算法与数据结构中,基础中的基础递归 ...

  3. ssm插入数据时候栈溢出_程序员算法与数据结构基础中的基础,栈与递归

    在此之前,我们介绍了动态规划.深度优先搜索等基础算法,但是,有部分好友评论说,难度太难了,我们知道动态规划的自顶向下跟深度优先搜索一般都用递归实现,今天我们就先来讲讲算法与数据结构中,基础中的基础递归 ...

  4. 关于值类型和引用 类型

    -----------------------------------------关于值 类型 和 引用 类型--------------------------------------------- ...

  5. python开始之路—基础中的基础

    python之路: 基础篇 一.Python 1.python是怎么来的     是在1989年吉多·范罗苏姆,在圣诞节的时候闲着无聊自己用C语言开发的,一个脚本解释程序,作为ABC语言的一种继承. ...

  6. 值类型 与引用的 copy

    结构体和枚举是值类型 值类型被赋予给一个变量,常数或者本身被传递给一个函数的时候,实际上操作的是其的拷贝. 在之前的章节中,我们已经大量使用了值类型.实际上,在 Swift 中,所有的基本类型:整数( ...

  7. 函数返回值是否使用引用类型的问题:理解引用、返回值

    在<对象更有用的玻璃罩--常引用>一文中,介绍了对象作为函数的参数时,推荐使用引用的形式.并且,如果实际参数的值不允许改变时,声明为常引用更佳. 在<第8周-任务1-方案3-复数类中 ...

  8. Java基础中的基础

    Java简介 jdk:Java开发工具包 jre:Java运行环境 如果想要运行java程序,只需要jre. 很多java开发的工具,里边自带jre. Java,原来是sun公司开发,后来被oracl ...

  9. 栈溢出原理 小记 基础中的基础~~

    原文地址:https://ctf-wiki.github.io/ctf-wiki/pwn/linux/stackoverflow/stackoverflow-basic-zh/ 自己的理解: 栈溢出指 ...

最新文章

  1. 牛客算法周周练2 B Music Problem(DP,抽屉原理,二进制拆分)
  2. 无法嵌入互操作类型 请改用适用的接口。
  3. Perl 之 use(), require(), do(), %INC and @INC
  4. Vue.js过滤器概述
  5. altium导出钻孔文件_[Altium Designer 学习]怎样输出Gerber文件和钻孔文件
  6. 在JSP中使用JavaBean
  7. 题目1140:八皇后
  8. Javascript归并排序
  9. locate用主动还是被动_已婚女人VS未婚女人,你觉得女人是应该主动出击还是被动接受?...
  10. Linux实战教学笔记29:MySQL数据库企业级应用实践
  11. 数据分析师初级—中级—高级,每个阶段都需要学习什么?
  12. sentaurus的SDE仿真基本流程
  13. python符号或非并列,Python运算符
  14. 《 ERP高级计划》书的解读之零物料约束和能力约束逻辑(蔡颖)(转)
  15. springboot-vue前后端分离登录
  16. usermod--修改用户账号信息命令
  17. golang日志库zerolog使用记录
  18. 爬虫实战——绝对通俗易懂,爬取房产数据
  19. 计算机专业理科二本录取分数线,理科二本大学排名及分数线
  20. w7系统出现无法更新服务器,win7系统自动更新选项不能用了的解决方法

热门文章

  1. 【代码笔记】Web-ionic-select
  2. 我的博客是怎么自定义的
  3. ecshop获取客户端操作系统
  4. Bluetooth LE(低功耗蓝牙) - 第一部分
  5. Ajax.ActionLink 辅助方法实现局部刷新
  6. Coder-Strike 2014 - Finals (online edition, Div. 2) A. Pasha and Hamsters
  7. 【ASP.NET Web API教程】5.4 ASP.NET Web API批处理器
  8. group by rollup
  9. python网页表格读取_是否可以读取网页html表格数据?
  10. java 导入导出txt文件_Java读取和写入txt文件