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

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

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

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

 

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

        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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/370277.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java 7:使用NIO.2进行文件过滤–第3部分

大家好。 这是使用NIO.2系列进行文件过滤的第3部分。 对于那些尚未阅读第1 部分或第2部分的人 ,这里有个回顾。 NIO.2是自Java 7起JDK中包含的用于I / O操作的新API。使用此新API,您可以执行与java.io相同的操作,以及许多出色的功能&#xf…

Hadoop Serialization -- hadoop序列化具体解释 (2)【Text,BytesWritable,NullWritable】

回想:回想序列化,事实上原书的结构非常清晰,我截图给出书中的章节结构:序列化最基本的,最底层的是实现writable接口,wiritable规定读和写的游戏规则 (void write(DataOutput out) throws IOExce…

我需要多少个线程?

这取决于您的应用程序。 但是对于那些希望对如何从生产站点购买的所有昂贵内核中挤出更多资金的人来说,请多多包涵,我将阐明围绕多线程 Java应用程序的奥秘。 内容针对最典型的Java EE应用程序进行了“优化”,该应用程序具有Web前端&#xff…

H5网页适配 iPhoneX,就是这么简单

iPhoneX 取消了物理按键,改成底部小黑条,这一改动导致网页出现了比较尴尬的屏幕适配问题。对于网页而言,顶部(刘海部位)的适配问题浏览器已经做了处理,所以我们只需要关注底部与小黑条的适配问题即可&#…

数字校园-云资源平台 2014.10.26-人人通共享空间

近期,教育部在统计学校信息化建设情况,当中一项重要内容,作为三通两平台的一个环节,就是学校开通人人通空间的情况,网上普及了一下知识,不就是十多年前就玩的学校博客的变种吗,网上有一些产品,也是没有热闹起来,为要求而要求的多,既然要求,就来一个吧,花了几天时间,也做了一个.…

Lucene –快速添加索引和搜索功能

什么是Lucene? Apache LuceneTM是完全用Java编写的高性能,功能齐全的文本搜索引擎库。 它是一项适用于几乎所有需要全文搜索的应用程序的技术,尤其是跨平台的应用程序。 Lucene可以纯文本,整数,索引PDF,Of…

《深入理解Java虚拟机》读书笔记3--垃圾回收算法

转载:http://blog.csdn.net/tjiyu/article/details/53983064 下面先来了解Java虚拟机垃圾回收的几种常见算法:标记-清除算法、复制算法、标记-整理算法、分代收集算法、火车算法,介绍它们的算法思路,有什么优点和缺点,…

Flex布局(一)flex-direction

采用Flex布局的元素,被称为Flex容器(flex container),简称"容器"。其所有子元素自动成为容器成员,成为Flex项目(Flex item),简称"项目" Flex-direction调整主轴方向(默认为水平方向)包…

登录网页后要弹出一个新标签_连永久链接都不会,还做什么新媒体?

上次给主编大大发的预览链接失效了,被骂得狗血淋头。大部分运营人可能都遇到过这种情况,忽视了预览生成的链接只是临时的,在12小时后或超过500阅读量后就会失效。一个疏忽,给自己带来了不必要的麻烦,耽误工作&#xff…

static_cast与dynamic_cast转换

static_cast与dynamic_cast转换   一 C语言中存在着两种类型转换: 隐式转换和显式转换 隐式转换:不同数据类型之间赋值和运算,函数调用传递参数……编译器完成 char ch;int i ch; 显示转换:在类型前增加 :&#xff…

vue使用iview Timeline 时间轴不显示问题

vue Timeline 时间轴不显示渲染的效果 官网代码 <Timeline pending><TimelineItem>发布1.0版本</TimelineItem><TimelineItem>发布2.0版本</TimelineItem><TimelineItem>发布3.0版本</TimelineItem><TimelineItem><a href…

Java EE 6 Web配置文件。 在云上。 简单。

Java SE还可以。 Java EE是邪恶的。 这就是我一直想的。 好吧&#xff0c;现在不再了。 让我分享我的经验。 几周前&#xff0c;我开始考虑将旧版spring hibernate tomcat应用程序移植到新平台上&#xff1a; SAP NetWeaver云 。 我知道您在极客那里的想法&#xff1a;…

Kubernetes核心概念总结

1、基础架构 1.1 Master Master节点上面主要由四个模块组成&#xff1a;APIServer、scheduler、controller manager、etcd。 APIServer。APIServer负责对外提供RESTful的Kubernetes API服务&#xff0c;它是系统管理指令的统一入口&#xff0c;任何对资源进行增删改查的操作都要…

php连接mysql数据,php连接mysql数据库

$sql_link mysql_connect("主机名","登入用户名","登入用户名密码");如果连接成功&#xff0c;就会返回一个mysql句柄,可以简单的理解成这个$sql_link 是php跟mysql的一个桥梁&#xff0c;通过该桥梁我们可以进入到mysql。进入到mysql之后&…

url存在宽字节跨站漏洞_利用WebSocket跨站劫持(CSWH)漏洞接管帐户

在一次漏洞悬赏活动中&#xff0c;我发现了一个使用WebSocket连接的应用&#xff0c;所以我检查了WebSocket URL&#xff0c;发现它很容易受到CSWH的攻击(WebSocket跨站劫持)有关CSWH的更多详细信息&#xff0c;可以访问以下链接了解https://www.christian-schneider.net/Cross…

php 数组对比 unset,如何区分PHP中unset,array_splice的区别

1.使用的函数a.函数unset()unset ( mixed $var , mixed $... ? ) : voidunset()销毁指定的变量。b.函数array_slice()array_splice(array,start,length,array)array表示数组。start表示删除元素的开始位置。length表示被移除的元素个数&#xff0c;也是被返回数组的长度。(可…

前端基础-CSS的各种选择器的特点以及CSS的三大特性

一、 基本选择器二、 后代选择器、子元素选择器三、 兄弟选择器四、 交集选择器与并集选择器五、 序列选择器六、 属性选择器七、 伪类选择器八、 伪元素选择器九、 CSS三大特性 一、 基本选择器 1、id选择器 #1、作用&#xff1a;根据指定的id名称&#xff0c;在当前界面中找…

使用JavaCV进行手和手指检测

这篇文章是Andrew Davison博士发布的有关自然用户界面&#xff08;NUI&#xff09;系列的一部分&#xff0c;内容涉及使用JavaCV从网络摄像头视频提要中检测手。 注意&#xff1a;可以从http://fivedots.coe.psu.ac.th/~ad/jg/nui055/下载本章的所有源代码。 第5章的彩色斑点检…

不能装载文档控件。请在检查浏览器的选项中检查浏览器的安全设置_【2020年网络安全宣传周】如何正确设置浏览器...

李夏是一个公司的职员&#xff0c;一天晚上加班赶制文档&#xff0c;由于要向客户汇报产品情况&#xff0c;需要获取大量网上信息&#xff0c;然而在制作中却发现浏览器的网页打不开了。第二天原计划向客户展示的材料未能完整汇总&#xff0c;客户见面对接效果也打了折扣。在当…

用装饰器设计模式装饰

装饰图案是广泛使用的结构图案之一。 此模式在运行时动态更改对象的功能&#xff0c;而不会影响对象的现有功能。 简而言之&#xff0c;此模式通过包装将附加功能添加到对象。 问题陈述&#xff1a; 想像一下我们有一个比萨饼&#xff0c;该比萨饼已经用番茄和奶酪烤制的情况。…