大家好我是白澤。
這篇打算講講java開發(fā)中新人要知道的一些事情吧
對象引用和值引用剿吻,這個(gè)是在基礎(chǔ)不過的知識(shí)了窍箍,但好多人特別是小白經(jīng)常會(huì)忽略這問題,lz當(dāng)初也是丽旅。如果你是大乓可以當(dāng)看看或者直接跳過唄。
提到這個(gè)概念我們先來大概了解下java中堆棧的東西榄笙,老話再談邪狞,“棧”是存放java對象中的基本組成數(shù)據(jù)也就是所謂的基本數(shù)據(jù)類型和對象的引用茅撞,棧里的東西執(zhí)行時(shí)都是單線程帆卓,你也可以理解為當(dāng)有線程訪問棧里的東西時(shí)棧都會(huì)克隆出一份新的讓新線程操作,所以棧里的東西一般不存在線程安全問題米丘。而“堆”存放就就是對象的信息棧中的引用會(huì)指向堆中這塊對應(yīng)的內(nèi)存剑令,在堆里一個(gè)對象只有一塊內(nèi)存,但可以被棧中多個(gè)引用地址引用拄查,這就會(huì)出現(xiàn)一個(gè)應(yīng)用改了這個(gè)對象其他引用取到的值也會(huì)相應(yīng)的變化吁津,這就會(huì)存在線程安全問題。當(dāng)然線程這東西比較不好理解堕扶,這篇博客也不是和大家講線程的所以大家只要知道棧中的數(shù)據(jù)一般不存在線程安全問題碍脏,而堆中的數(shù)據(jù)就會(huì)有線程安全問題暫時(shí)就夠了。
今天我們要講的是我們平常開發(fā)必不可少的操作“傳參”稍算,傳參就是往一個(gè)方法中傳遞參數(shù)潮酒,那這個(gè)又有什么好注意的呢?讓lz一一道來邪蛔,首先參數(shù)部分會(huì)有基本數(shù)據(jù)類型和對象引用構(gòu)成那這個(gè)基礎(chǔ)數(shù)據(jù)類型就是我們今天要講的值傳遞扎狱,而對象引用就是對象的引用傳遞。大家也可以暴力一點(diǎn)記成在java中的參數(shù)里基礎(chǔ)數(shù)據(jù)類型的參數(shù)就是值傳遞匠抗,對象就是一個(gè)引用傳遞污抬。在這里新人要注意的是傳進(jìn)來的的參數(shù)如果是值引用可以隨便的修改绳军,因?yàn)樯厦嬲f過它是存放在棧中是線程安全的门驾,每次訪問都會(huì)復(fù)制出一份出來所以相互之間不會(huì)影響奶是。而引用傳遞就不是這樣竣灌。首先需要注意的是,如果傳進(jìn)來的對象有這么個(gè)需求“你想用別人寫的對象然后將它的引用作為方法參數(shù)傳進(jìn)來”那么這個(gè)對象在你的方法中切記千萬不要直接的修改該類的數(shù)據(jù)和狀態(tài)及汉。因?yàn)榭赡苤皇悄阆胍@個(gè)對象的數(shù)據(jù)變化而寫這個(gè)對象的同事或者其他使用這個(gè)對象的同事并不希望這對象的值有變化坷随,這時(shí)你要是直接修改的話那就會(huì)出現(xiàn)后期可能連你自己都不知道的bug而且這種bug不容易找出來漫贞。為什么會(huì)出現(xiàn)這種情況呢?上面提到過芍殖,對象是放在堆中的如果你使用的時(shí)候不是重新new出來一個(gè)那么你使用的引用也是指向和別人使用的同一塊內(nèi)存谴蔑,這樣你改了別人當(dāng)然也會(huì)有變化。這其實(shí)也算是一種線程安全的表現(xiàn)吧窃躲。
那么如何避免這種bug呢钦睡?首先如果你只是想用這個(gè)對象而不是對象里的別人的數(shù)據(jù),那你只要自己new出來然后自己賦值初始化再傳進(jìn)去就可以洒琢。因?yàn)槭褂胣ew關(guān)鍵字創(chuàng)建的對象會(huì)在堆內(nèi)存中分配一個(gè)新的內(nèi)存給你這個(gè)對象褐桌,同樣在棧中也會(huì)生成一個(gè)新的引用給你。那要是想用別人的數(shù)據(jù)呢呛踊?這就要使用克隆的方法去把該對象克隆出來再使用或者自己提供一個(gè)該對象的克隆方法即:new出一個(gè)新對象之后再把另一個(gè)對象的數(shù)據(jù)set進(jìn)去再使用就好。另外比較快捷的方式就是實(shí)現(xiàn)java提供的Cloneable接口重寫它的clone方法再使用谭网,但這個(gè)方法只是淺復(fù)制,也就是說它只會(huì)復(fù)制對象里存在棧里邊的數(shù)據(jù)也就是基本數(shù)據(jù)類型的數(shù)據(jù)骄崩,而如果這個(gè)對象有其他對象的引用那么如果你修改那個(gè)被引用的對象還是會(huì)被修改掉薄辅,除非你再使用這個(gè)方法再給那個(gè)對象進(jìn)行克隆站楚。但是這種方式是不是聽著就感覺很low?窿春,別急,試試下一種蔚润。就是實(shí)現(xiàn)java提供的Serializable序列化接口再使用io對其進(jìn)行序列化嫡纠,再反序列化回來的對象就是一個(gè)全新的對象延赌,也就是說在堆中有自己的內(nèi)存地址,對其修改不會(huì)影響別人的對象的數(shù)據(jù)挫以。
下面看一個(gè)內(nèi)存圖掐松,其中有兩個(gè)對象引用同時(shí)指向同一個(gè)對象,而此時(shí)一個(gè)修改數(shù)據(jù)泻仙,一個(gè)獲取數(shù)據(jù)但是操作的都是同一個(gè)對象的數(shù)據(jù)這樣就會(huì)參生數(shù)據(jù)錯(cuò)亂的額情況
好了量没,第一遍入行博客就寫到這了殴蹄,以后講講在工作中的經(jīng)驗(yàn)和積累,大家有興趣可以關(guān)注微信公眾號 baize1935 獲取更過文章刺下。