首頁 > 軟體

java 參照傳遞的三種型別小結

2022-02-15 16:00:14

java參照傳遞的三種型別

我這裡使用了mldn視訊裡的例子,只用於學習交流。

第一種

結果:呼叫前:50

呼叫後:1000

分析:

理解:好理解

第二種傳遞方式

先看例子

執行結果:

分析圖片:

第三種傳遞方式

結果:

分析:

對於三種參照傳遞的理解

第一種和第三種都好理解:

其實就是c語言那樣傳遞的是地址,當然能夠修改屬性值,對於第二種其實就是因為String類比較特殊,在第二個例子中fun()函數str2="mldn"其實mldn是個匿名物件!!!這個等式其實就是將str2的參照的地址值改變了,也即使str1的參照地址指向了mldn這個在堆記憶體的這個物件。

java參照傳值問題

一圖勝萬言(配上一張啟艦大神的圖,一個自定義控制元件寫的很吊的大神):

這幾天一直在寫一個專案,果然只搞理論是不行的,距離上一次寫專案已經快有半年了,今天無論是效率還是熟練度都大不如前

好了言歸正傳,今天要說的這個問題其實很簡單——在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);
        ......
    }

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com