【基礎中的基礎】引用類型和值類型,以及引用傳遞和值傳遞

一直在博客園懟人,非常慚愧。所以鄭重決定:

好好寫一篇干貨,然后再接著懟人。

這是一起幫上陳百萬同學的求助,講了一會之后,我覺得很有些普世價值,干脆就發到園子來。面向小白,高手輕拍。

?

我們從最簡單的說起(基礎知識,懂的同學直接往下拉),直接上代碼:

        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.pswp.cn/news/370277.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/370277.shtml
英文地址,請注明出處:http://en.pswp.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…

python眾數問題給定含有n個元素的多重集合s_分治法求眾數 給定含有n個元素的多重集合S 聯合開發網 - pudn.com...

分治法求眾數所屬分類:數據結構開發工具:C/C文件大小:240KB下載次數:3上傳日期:2018-01-04 20:19:09上 傳 者:九鼎說明: 給定含有n個元素的多重集合S,每個元素在S中出現的次數稱為該…

mysql 5.0 亂碼,解決MySQL 5.0.16的亂碼問題

導讀:問:怎樣解決MySQL 5.0.16的亂碼問題?答:MySQL 5.0.16的亂碼問題可以用下面的方法解決:1.設置phpMyAdminLanguage:Chinese simplified (zh-utf-8)MySQL 字符集:UTF-8 Unicode (utf8)MySQL 連接校對 gbk_chinese_c…

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

回想:回想序列化,事實上原書的結構非常清晰,我截圖給出書中的章節結構:序列化最基本的,最底層的是實現writable接口,wiritable規定讀和寫的游戲規則 (void write(DataOutput out) throws IOExce…

我需要多少個線程?

這取決于您的應用程序。 但是對于那些希望對如何從生產站點購買的所有昂貴內核中擠出更多資金的人來說,請多多包涵,我將闡明圍繞多線程 Java應用程序的奧秘。 內容針對最典型的Java EE應用程序進行了“優化”,該應用程序具有Web前端&#xff…

H5網頁適配 iPhoneX,就是這么簡單

iPhoneX 取消了物理按鍵,改成底部小黑條,這一改動導致網頁出現了比較尷尬的屏幕適配問題。對于網頁而言,頂部(劉海部位)的適配問題瀏覽器已經做了處理,所以我們只需要關注底部與小黑條的適配問題即可&#…

python為什么closed_為什么python類的函數被調用兩次[關閉](Why a function of python class is called twice [closed])...

為什么python類的函數被調用兩次[關閉](Why a function of python class is called twice [closed])我遇到了兩次調用的python類函數的問題。 我正在使用Spyder IDE。這是我的簡單代碼class Test:def f(self):print("a")from Test import *t Test()t.f()當我按“運行…

php關聯數組和哈希表,php遍歷哈希表及關聯數組的實例代碼

有關php數組的分類,PHP數組分為:數字索引數組和關聯數組。其中數字索引數組和C語言中的數組一樣,下標是為0,1,2…而關聯數組下標可能是任意類型,與其它語言中的hash,map等結構相似。PHP遍歷關聯…

數字校園-云資源平臺 2014.10.26-人人通共享空間

近期,教育部在統計學校信息化建設情況,當中一項重要內容,作為三通兩平臺的一個環節,就是學校開通人人通空間的情況,網上普及了一下知識,不就是十多年前就玩的學校博客的變種嗎,網上有一些產品,也是沒有熱鬧起來,為要求而要求的多,既然要求,就來一個吧,花了幾天時間,也做了一個.…

VUE.js 中取得后臺原生HTML字符串 原樣顯示問題

今天使用vue調試頁面,發現了頁面上的一個問題,后臺數據傳過來的HTML字符串并沒有被轉換為正常的HTML代碼,一拍腦門,發現忘記轉換了,于是滿心歡喜加上了{{{}}}。但是之后構建發現報錯: 為此去官網上查了下…

高性能持久消息

總覽 盡管有許多可用于Java的高性能消息傳遞系統,但大多數都避免引用基準,包括持久消息傳遞和消息的序列化/反序列化。 這樣做有很多原因。 1)您并不總是需要或想要持久消息2)您希望使用自己的序列化選項。 避免使用它們的一個重要…

python去掉重復內容并按原來次序輸出元素_在Python中,從列表中刪除重復項以使所有元素在保留順序時都是唯一的最快的算法是什么?...

飲歌長嘯使用方法:lst [8, 8, 9, 9, 7, 15, 15, 2, 20, 13, 2, 24, 6, 11, 7, 12, 4, 10, 18, 13, 23, 11, 3, 11, 12, 10, 4, 5, 4, 22, 6, 3, 19, 14, 21, 11, 1, 5, 14, 8, 0, 1, 16, 5, 10, 13, 17, 1, 16, 17, 12, 6, 10, 0, 3, 9, 9, 3, 7, 7, 6, 6, 7, 5, 1…

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

什么是Lucene? Apache LuceneTM是完全用Java編寫的高性能,功能齊全的文本搜索引擎庫。 它是一項適用于幾乎所有需要全文搜索的應用程序的技術,尤其是跨平臺的應用程序。 Lucene可以純文本,整數,索引PDF,Of…

td 雙擊 編輯 php,雙擊表格td進行編輯

$(function(){//隔行換色// $("tbody tr:odd").css("background-color","#eee");var numId $(".tbody td");numId.dblclick(function(){var tdIns $(this);var tdpar $(this).parents("tr");//tdpar.remove();//current_…

前端開發之基礎知識-HTML(一)

1.1 html概述和基本結構 html概述 HTML是 HyperText Mark-up Language 的首字母簡寫,意思是超文本標記語言,超文本指的是超鏈接,標記指的是標簽,是一種用來制作網頁的語言,這種語言由一個個的標簽組成,用…

nodejs的async異步編程

函數有: series waterfall parallel parallelLimit … series函數 串行執行 它的作用就是按照順序一次執行。 async.series({ one: function(callback){ callback(null, 1); }, two: function(callback){ callback(null, 2); } },function(err, results) { conso…

《深入理解Java虛擬機》讀書筆記3--垃圾回收算法

轉載:http://blog.csdn.net/tjiyu/article/details/53983064 下面先來了解Java虛擬機垃圾回收的幾種常見算法:標記-清除算法、復制算法、標記-整理算法、分代收集算法、火車算法,介紹它們的算法思路,有什么優點和缺點,…

python常用函數中文_【python】python常用函數

urlencode與urldecode當url中包含中文或者參數包含中文,需要對中文或者特殊字符(/、&)做編碼轉換。urlencode的本質:把字符串轉為gbk編碼,再把\x替換成%。如果終端是utf8編碼的,需要把結果再轉成utf8輸出,否則會亂…

帶有批注的Spring硒測試

這篇文章描述了如何在Java中實現Selenium測試。 它的靈感來自Alex Collins的帖子,并帶有注釋。 該代碼可在GitHub的Spring-Selenium-Test目錄中找到。 一些替代方法和更輕巧的技術可用于對Spring MVC應用程序進行單元測試。 要進行單元測試服務,請參見此…

sizeof運算符

sizeof是一個單目運算符&#xff0c;它的運算對象是變量或數據類型&#xff0c;運算結果為一個整數。運算的一般形式如下: sizeof(<類型或變量名>) 它只針對數據類型&#xff0c;而不針對變量&#xff01; 若運算對象為變量&#xff0c;則所求的結果是這個變量占用的內存…