java?引用傳遞的三種類型小結(jié)
java引用傳遞的三種類型
我這里使用了mldn視頻里的例子,只用于學(xué)習(xí)交流。
第一種
結(jié)果:調(diào)用前:50
調(diào)用后:1000
分析:
理解:好理解
第二種傳遞方式
先看例子
運(yùn)行結(jié)果:
分析圖片:
第三種傳遞方式
結(jié)果:
分析:
對(duì)于三種引用傳遞的理解
第一種和第三種都好理解:
其實(shí)就是c語言那樣傳遞的是地址,當(dāng)然能夠修改屬性值,對(duì)于第二種其實(shí)就是因?yàn)镾tring類比較特殊,在第二個(gè)例子中fun()函數(shù)str2="mldn"其實(shí)mldn是個(gè)匿名對(duì)象?。?!這個(gè)等式其實(shí)就是將str2的引用的地址值改變了,也即使str1的引用地址指向了mldn這個(gè)在堆內(nèi)存的這個(gè)對(duì)象。
java引用傳值問題
一圖勝萬言(配上一張啟艦大神的圖,一個(gè)自定義控件寫的很吊的大神):
這幾天一直在寫一個(gè)項(xiàng)目,果然只搞理論是不行的,距離上一次寫項(xiàng)目已經(jīng)快有半年了,今天無論是效率還是熟練度都大不如前
好了言歸正傳,今天要說的這個(gè)問題其實(shí)很簡(jiǎn)單——在java中的參數(shù)傳遞問題。(其實(shí)我承認(rèn),這個(gè)地方我只是知道對(duì)象傳引用、普通類型傳值,典型的理論派-。+),但是這個(gè)問題可大可小,我覺得還是要把這些縷得清清楚楚才好。
問題起源,一個(gè)蠢到家的是失敗案例
其實(shí)今天寫這篇文章完全是咋呼-。+,恰好是因?yàn)樽约涸谧鯮ecyclerView的萬能適配器的時(shí)候出現(xiàn)的問題,先給大家引入一下當(dāng)時(shí)的場(chǎng)景:
@Override public void resultCallbackFromFragment(List<Contact> list) { Toast.makeText(this, "修改成功!", Toast.LENGTH_SHORT).show(); ...... contactList = list; adapter.notifyDataSetChanged(); ...... }
只留下了我們?cè)O(shè)計(jì)的代碼,其他部分的代碼全部打……了。接下來我用極其簡(jiǎn)單的組織語言介紹一下場(chǎng)景:
打開一個(gè)具有復(fù)選框的界面,退出時(shí)返回選中的數(shù)據(jù),方法為一個(gè)回調(diào)方法,方法的效果是更新列表數(shù)據(jù)(contactList為我們傳入RecyclerView的源數(shù)據(jù))。
理論上說先給contactList更新為獲取到的最新的值,然后調(diào)用notifyDataSetChanged方法,列表就刷新了,看上去一切都是那么的圓滿。然后我們看一下效果:
不要吐槽這個(gè)App背景,因?yàn)槭墙o我的小仙女做的-。+!
在上面的效果中,我們看到,在選中了兩個(gè)聯(lián)系人,點(diǎn)擊確定之后,按道理說應(yīng)該是顯示成兩個(gè)人,怎么還是剛才的數(shù)據(jù)呢?
當(dāng)時(shí)也是知道引用類型的傳遞傳遞的是引用,回憶了一下自己當(dāng)時(shí)的思路:引用傳遞給了另一個(gè)引用,這一個(gè)引用的內(nèi)容改變了,所有的都改變了。。。。 (可能有的朋友看到我這句話覺得很好笑:哇博主你好菜啊,這么基礎(chǔ)的問題都被繞住了,好吧我得承認(rèn)java基礎(chǔ)是有些差。。)
就是這么簡(jiǎn)單的一句話讓我饒了好幾個(gè)大彎,當(dāng)時(shí)自己已經(jīng)被繞進(jìn)去了,覺得這個(gè)數(shù)據(jù)就是被改變了啊,然后就開始從其他地方找錯(cuò)誤,過了好久才開始反思:是不是數(shù)據(jù)傳遞的過程出現(xiàn)了點(diǎn)問題-。+
然后自己就開始查找參數(shù)傳遞相關(guān)問題,好了,現(xiàn)在開始,我們先跳出上面這個(gè)案例中,我不希望大家被上面花里胡哨的東西影響,因?yàn)槲覀兘裉熘v的問題只有一個(gè):java的引用傳值。
兩類參數(shù)傳遞
參數(shù)傳遞主要分為兩種:一種是參數(shù)是基本類型,一種是參數(shù)為引用類型。
基本數(shù)據(jù)類型
這個(gè)相信大家都沒什么問題,基本類型作為參數(shù)傳遞的時(shí)候是在一個(gè)方法棧中開辟了一塊新內(nèi)存,拷貝了原來的數(shù)據(jù)值,所以無論我們?nèi)绾涡薷?,原來的?shù)據(jù)值不會(huì)受到任何影響。
舉個(gè)簡(jiǎn)單的栗子:
public class Practice2 { public static void main(String[] args) { // TODO Auto-generated method stub int a = 5; System.out.println(a); change(a); System.out.println(a); } public static void change(int b) { b = 500; } }
結(jié)果如下:
5
5
沒有任何變化,對(duì)吧。
引用數(shù)據(jù)類型
首先我們要知道引用的數(shù)據(jù)存儲(chǔ)在棧內(nèi)存中,而引用指向的對(duì)象存儲(chǔ)在堆內(nèi)存中。
當(dāng)引用作為方法參數(shù)傳遞給方法的時(shí)候,是將引用的值拷貝一份給另一個(gè)引用,但引用指向的都是同一個(gè)堆內(nèi)存,所以進(jìn)行的修改操作同樣有效。
實(shí)例代碼:
public class Practice { static A a = new A(10); public static void main(String[] args) { // TODO Auto-generated method stub Practice practice = new Practice(); System.out.println(practice.a.intData); change(practice.a); System.out.println(practice.a.intData); } public static void change(A aa) { aa.intData = 500; System.out.println(aa.intData); } } class A{ int intData; public A(int intData) { this.intData = intData; } }
10
500
這么說起來沒什么難度,對(duì)吧。
引用傳遞
其實(shí)上面所說的引用形參傳遞,本質(zhì)上就是引用的傳遞,我們將引用傳遞給了另一個(gè)引用,那么這兩個(gè)引用都有了相同的值——既指向了相同的對(duì)象。
A a1 = new A(10); A a2 = a1; System.out.println("a1的intData: " + a1.intData + " a2的intData: " + a2.intData ); a2.intData = 500; System.out.println("a1的intData: " + a1.intData + " a2的intData: " + a2.intData );
結(jié)果如下:
a1的intData: 10 a2的intData: 10
a1的intData: 500 a2的intData: 500
注意):引用類型中,形參能夠改變實(shí)參的值,或者一個(gè)引用能夠改變另一個(gè)引用的值,僅僅是因?yàn)樗麄儣?nèi)存中存儲(chǔ)的值相同,但這個(gè)值是隨時(shí)可以修改的。
這個(gè)也就是本人之前一直被困住的地方,其實(shí)只要引用存儲(chǔ)的值改變了,這兩個(gè)引用就毫無關(guān)系了。請(qǐng)見下面的例子:
A a1 = new A(); A a2 = a1; System.out.println(a1); System.out.println(a2); a2 = new A(); System.out.println(a1); System.out.println(a2);
結(jié)果如下:
A@33909752
A@33909752
A@33909752
A@55f96302
在a2指向新的對(duì)象后,a1和a2就已經(jīng)沒有任何關(guān)系了,因?yàn)樗麄儍蓚€(gè)引用存儲(chǔ)的值已經(jīng)完全不一樣了。
相信這張圖已經(jīng)說的很明白了吧。
反過來再解決這個(gè)案例
現(xiàn)在有了上面的理論知識(shí),我們?cè)诜催^頭來看一開始的這個(gè)問題。
@Override public void resultCallbackFromFragment(List<Contact> list) { Toast.makeText(this, "修改成功!", Toast.LENGTH_SHORT).show(); ...... contactList = list; adapter.notifyDataSetChanged(); ...... }
在我們獲取到了新的list之后,是給contactList賦值了一個(gè)新的引用,此時(shí)他指向的為一個(gè)新的堆內(nèi)存空間。但是適配器中的list還是指向之前的引用,因?yàn)槲覀冎皇歉淖兞薱ontactList引用的值,然后執(zhí)行notifyDataSetChanged方法,可是適配器中l(wèi)ist數(shù)據(jù)還是原來contactList指向的數(shù)據(jù)。
因此解決的辦法是:直接改變適配器中的list引用,然后調(diào)用notifyDataSetChanged方法:
public void notifyData(List<T> mList){ this.mList = mList; notifyDataSetChanged(); }
直接在適配器中寫一個(gè)修改數(shù)據(jù)的方法,然后在外面調(diào)用就好啦:
@Override public void resultCallbackFromFragment(List<Contact> list) { Toast.makeText(this, "修改成功!", Toast.LENGTH_SHORT).show(); ...... contactList = list; adapter.notifyData(contactList); ...... }
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot war包部署到Tomcat服務(wù)器
這篇文章主要介紹了SpringBoot war包部署到Tomcat服務(wù)器,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-03-03解析Java的可變長參數(shù)列表及其使用時(shí)的注意點(diǎn)
這篇文章主要介紹了解析Java的可變參數(shù)列表及其使用時(shí)的注意點(diǎn),注意可變參數(shù)必須位于最后一項(xiàng),需要的朋友可以參考下2016-03-03用Spring Native將SpringBoot程序轉(zhuǎn)換為GraalVM
這篇文章主要介紹了用Spring Native將SpringBoot程序轉(zhuǎn)換為GraalVM的方法,幫助大家更好的理解和學(xué)習(xí)使用SpringBoot,感興趣的朋友可以了解下2021-04-04mybatis一對(duì)多兩種mapper寫法實(shí)例
這篇文章主要介紹了mybatis一對(duì)多兩種mapper寫法實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12全面解析SpringBoot自動(dòng)配置的實(shí)現(xiàn)原理
這篇文章主要介紹了全面解析SpringBoot自動(dòng)配置的實(shí)現(xiàn)原理的相關(guān)資料,需要的朋友可以參考下2017-05-05