您好,登錄后才能下訂單哦!
前言
首先說觀點:java只有值傳遞沒有引用傳遞
然后再來看看值傳遞與引用傳遞兩者的定義
值傳遞(pass by value)是指在調用函數時將實際參數復制一份傳遞到函數中,這樣在函數中如果對參數進行修改,將不會影響到實際參數。
引用傳遞(pass by reference)是指在調用函數時將實際參數的地址直接傳遞到函數中,那么在函數中對參數所進行的修改,將影響到實際參數。
這里牢記值傳遞中將實際參數復制一份。
然后就是對于參數類型:值類型 和 引用類型。
結合起來理解就是:值類型傳遞,java是將其值內容復制一份給形參;對于引用類型傳遞,java是將其地址復制一份給形參。
下面結合實例深入理解為什么java只有值傳遞
package 字符串; public class 值傳遞 { public static void main(String[] args) { String str1="abc"; updateStr1(str1); System.out.println("main函數中"+str1); } public static void updateStr1(String str1) { str1="cba"; //<注解> System.out.println("調用函數中"+str1); } }
結果:
在這里我們能夠清晰看到我們傳遞的是String類型的對象即(引用類型),并且在調用函數中我們修改了str1為cba,如果是引用傳遞那么我們在主函數打印則應該是cba,
但是很遺憾我們在主函數中仍然打印出來的是abc。所以我們可以說java是值傳遞類型了嗎,答案是不完全的。
接下來再看這一段代碼:
package 字符串; public class person { private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } } public class 值傳遞2 { public static void main(String[] args) { person p1=new person(); p1.setAge(10); System.out.println("我在主函數里對p1的年齡屬性賦值為"+p1.getAge()); setage(p1); System.out.println("我再從主函數里獲取P1的年齡屬性"+p1.getAge()); } public static void setage(person p1) { p1.setAge(18); //不是我們對它的地址進行了操作,而是我們對它地址的內容進行了操作 System.out.println("我在調用函數里對p1的年齡屬性重新賦值為"+p1.getAge()); } }
結果:
咦,怎么回事這次也是傳遞的對象(引用類型),為什么這次我們對年齡這個字段的修改在主函數同步了呢?
別急,下面我們先來分析這兩個例子。
首先第一個類型的例子中,我們傳遞的是String類型的變量,它是一個特殊的類型的引用變量。
(不可變字符串:編譯器可讓字符串共享,即將各種字符串存放于公共存儲池中,字符串變量是指向其中相應位置 --出自《Java核心技術 卷1》)
出于這句話的理解就是每個字符串都對應一個地址:我們例一中是將str1的地址復制給了我們的形參str1,并且形參中str1的地址進行了改變指向了“cba”的地址。所以說在主函數中的str1的地址仍然指向的是“abc”所對應的地址。
所以說對于String類型的變量,我們對于給它重新賦值不是改變了它的內容,而是改變了它指向字符串的位置。這也就解釋了為什么java中String類型是不可變類型。
而在我們例二中,我們將p1的地址復制給了我們形參中的p1,此時他們都指向的內存中一塊相同的地址這里存放著相同內容,所以我們在調用函數對這個地址中的內容進行修改時就會同步到我們主函數中的p1。所以這個并不意味著這個是引用傳遞。
好吧,那怎么才能解釋好Java確實是值傳遞呢(上面String類型例子是特殊的引用類型不方便解釋)
下面我們通過這個例子說明:
package 字符串; public class person { private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } } public class 值傳遞3 { public static void main(String[] args) { person p1=new person(); person p2=new person(); p1.setAge(10); p2.setAge(18); System.out.println("我在主函數里對p1的年齡屬性賦值為"+p1.getAge()); System.out.println("我在主函數里對p2的年齡屬性賦值為"+p2.getAge()); swap(p1,p2); System.out.println("************我是主函數里的分割線***************"); //我再在主函數里分別對p1,p2獲取他們的年齡,若為引用傳遞則p1的年齡應該為18,p2為10. System.out.println("我在主函數里獲取p1的年齡"+p1.getAge()); System.out.println("我在主函數里獲取p1的年齡"+p2.getAge()); } public static void swap(person p1,person p2) { System.out.println("************我是調用函數里的分割線***************"); person temp=new person(); temp=p1; p1=p2; p2=temp; System.out.println("我在調用函數里交換了p1和p2指向的地址"); System.out.println("我在調用函數里對p1的年齡屬性賦值為"+p1.getAge()); System.out.println("我在調用函數里對p2的年齡屬性賦值為"+p2.getAge()); } }
結果:
看到沒,這就是充分說明Java是值傳遞的例子。在這個例子中我們依然傳遞的是person類的對象p1,p2(引用類型),他們將各自的地址復制一份到了形參p1、p2。
然后我們在調用函數中交換了他們的地址,確實在調用函數中他們的age屬性發生交換。但是再當我們在主函數獲取他們的age時,如果是引用傳遞則應該p1的age為18,p2的age為10,
和我們在調用函數中打印結果一致。但是,很遺憾在主函數中他們的值仍然是p1(10),p2(18)。所以這也充分印證了java是值傳遞。
那么什么是引用傳遞呢?我們把代碼放入C#看看。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 值傳遞or引用傳遞 { public class person { private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } } class Program { static void Main(string[] args) { person p1 = new person(); person p2 = new person(); person p3 = new person(); p1.setAge(10); p2.setAge(18); p3.setAge(15); Console.WriteLine("我在主函數里對p1的年齡屬性賦值為" + p1.getAge()); Console.WriteLine("我在主函數里對p2的年齡屬性賦值為" + p2.getAge()); Console.WriteLine("我在主函數里對p3的年齡屬性賦值為" + p3.getAge()); swap(ref p1,ref p2,p3); Console.WriteLine("************我是主函數里的分割線***************"); //我再在主函數里分別對p1,p2獲取他們的年齡,若為引用傳遞則p1的年齡應該為18,p2為10. Console.WriteLine("我在主函數里獲取p1的年齡" + p1.getAge()); Console.WriteLine("我在主函數里獲取p2的年齡" + p2.getAge()); Console.WriteLine("我在主函數里獲取p3的年齡" + p3.getAge()); } public static void swap(ref person p1,ref person p2, person p3) { Console.WriteLine("************我是調用函數里的分割線***************"); person temp = new person(); temp = p1; p1 = p2; p2 = temp; p3.setAge(20); Console.WriteLine("我在調用函數里交換了p1和p2指向的地址"); Console.WriteLine("我在調用函數里對p1交換地址后年齡為" + p1.getAge()); Console.WriteLine("我在調用函數里對p2交換地址后年齡為" + p2.getAge()); Console.WriteLine("我在調用函數里修改p3年齡為" + p3.getAge()); } } }
結果:
請注意在C#中如果我們要實現引用傳遞,請加上關鍵字ref,否則,它執行的原理仍然與我們java中執行的機制一樣,即拷貝一份地址給形參。
如果你還有點暈,不妨我們來看看下面兩張圖。
為了方便大家理解把圖畫成這樣,然后關于java的值傳遞深度分析就到這里。歡迎大家一起討論。(可以打臉/哈哈)
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。