您好,登錄后才能下訂單哦!
小編給大家分享一下java引用傳遞的類型有哪些,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
結果:調用前:50
調用后:1000
分析:
理解:好理解
先看例子
運行結果:
分析圖片:
結果:
分析:
第一種和第三種都好理解:
其實就是c語言那樣傳遞的是地址,當然能夠修改屬性值,對于第二種其實就是因為String類比較特殊,在第二個例子中fun()函數str2="mldn"其實mldn是個匿名對象!!!這個等式其實就是將str2的引用的地址值改變了,也即使str1的引用地址指向了mldn這個在堆內存的這個對象。
一圖勝萬言(配上一張啟艦大神的圖,一個自定義控件寫的很吊的大神):
這幾天一直在寫一個項目,果然只搞理論是不行的,距離上一次寫項目已經快有半年了,今天無論是效率還是熟練度都大不如前
好了言歸正傳,今天要說的這個問題其實很簡單——在java中的參數傳遞問題。(其實我承認,這個地方我只是知道對象傳引用、普通類型傳值,典型的理論派-。+),但是這個問題可大可小,我覺得還是要把這些縷得清清楚楚才好。
其實今天寫這篇文章完全是咋呼-。+,恰好是因為自己在做RecyclerView的萬能適配器的時候出現的問題,先給大家引入一下當時的場景:
@Override public void resultCallbackFromFragment(List<Contact> list) { Toast.makeText(this, "修改成功!", Toast.LENGTH_SHORT).show(); ...... contactList = list; adapter.notifyDataSetChanged(); ...... }
只留下了我們設計的代碼,其他部分的代碼全部打……了。接下來我用極其簡單的組織語言介紹一下場景:
打開一個具有復選框的界面,退出時返回選中的數據,方法為一個回調方法,方法的效果是更新列表數據(contactList為我們傳入RecyclerView的源數據)。
理論上說先給contactList更新為獲取到的最新的值,然后調用notifyDataSetChanged方法,列表就刷新了,看上去一切都是那么的圓滿。然后我們看一下效果:
不要吐槽這個App背景,因為是給我的小仙女做的-。+!
在上面的效果中,我們看到,在選中了兩個聯系人,點擊確定之后,按道理說應該是顯示成兩個人,怎么還是剛才的數據呢?
當時也是知道引用類型的傳遞傳遞的是引用,回憶了一下自己當時的思路:引用傳遞給了另一個引用,這一個引用的內容改變了,所有的都改變了。。。。 (可能有的朋友看到我這句話覺得很好笑:哇博主你好菜啊,這么基礎的問題都被繞住了,好吧我得承認java基礎是有些差。。)
就是這么簡單的一句話讓我饒了好幾個大彎,當時自己已經被繞進去了,覺得這個數據就是被改變了啊,然后就開始從其他地方找錯誤,過了好久才開始反思:是不是數據傳遞的過程出現了點問題-。+
然后自己就開始查找參數傳遞相關問題,好了,現在開始,我們先跳出上面這個案例中,我不希望大家被上面花里胡哨的東西影響,因為我們今天講的問題只有一個:java的引用傳值。
參數傳遞主要分為兩種:一種是參數是基本類型,一種是參數為引用類型。
這個相信大家都沒什么問題,基本類型作為參數傳遞的時候是在一個方法棧中開辟了一塊新內存,拷貝了原來的數據值,所以無論我們如何修改,原來的數據值不會受到任何影響。
舉個簡單的栗子:
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; } }
結果如下:
5
5
沒有任何變化,對吧。
首先我們要知道引用的數據存儲在棧內存中,而引用指向的對象存儲在堆內存中。
當引用作為方法參數傳遞給方法的時候,是將引用的值拷貝一份給另一個引用,但引用指向的都是同一個堆內存,所以進行的修改操作同樣有效。
實例代碼:
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
這么說起來沒什么難度,對吧。
其實上面所說的引用形參傳遞,本質上就是引用的傳遞,我們將引用傳遞給了另一個引用,那么這兩個引用都有了相同的值——既指向了相同的對象。
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 );
結果如下:
a1的intData: 10 a2的intData: 10
a1的intData: 500 a2的intData: 500
注意):引用類型中,形參能夠改變實參的值,或者一個引用能夠改變另一個引用的值,僅僅是因為他們棧內存中存儲的值相同,但這個值是隨時可以修改的。
這個也就是本人之前一直被困住的地方,其實只要引用存儲的值改變了,這兩個引用就毫無關系了。請見下面的例子:
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);
結果如下:
A@33909752
A@33909752
A@33909752
A@55f96302
在a2指向新的對象后,a1和a2就已經沒有任何關系了,因為他們兩個引用存儲的值已經完全不一樣了。
相信這張圖已經說的很明白了吧。
現在有了上面的理論知識,我們在反過頭來看一開始的這個問題。
@Override public void resultCallbackFromFragment(List<Contact> list) { Toast.makeText(this, "修改成功!", Toast.LENGTH_SHORT).show(); ...... contactList = list; adapter.notifyDataSetChanged(); ...... }
在我們獲取到了新的list之后,是給contactList賦值了一個新的引用,此時他指向的為一個新的堆內存空間。但是適配器中的list還是指向之前的引用,因為我們只是改變了contactList引用的值,然后執行notifyDataSetChanged方法,可是適配器中list數據還是原來contactList指向的數據。
因此解決的辦法是:直接改變適配器中的list引用,然后調用notifyDataSetChanged方法:
public void notifyData(List<T> mList){ this.mList = mList; notifyDataSetChanged(); }
直接在適配器中寫一個修改數據的方法,然后在外面調用就好啦:
@Override public void resultCallbackFromFragment(List<Contact> list) { Toast.makeText(this, "修改成功!", Toast.LENGTH_SHORT).show(); ...... contactList = list; adapter.notifyData(contactList); ...... }
以上是“java引用傳遞的類型有哪些”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。