?java方法的調(diào)用中值的傳遞問題凉当,實(shí)際參數(shù)究竟什么時(shí)候才會改變?
public class Demo {
? ? ? ? public static void main(String[] args) {
? ? ? ? ? ? ? ? int a = 10;
? ? ? ? ? ? ? ? change(a);
? ? ? ? ? ? ? ? System.out.println(a);? // 1:請問輸出什么?
? ? ? ? ? ? ? ? String str = "abc";
? ? ? ? ? ? ? ? change(str);
? ? ? ? ? ? ? ? System.out.println(str);// 2:請問輸出什么愧旦?
? ? ? ? ? ? ? ? Student? s = new Student("張三",13);
? ? ? ? ? ? ? ? System.out.println(s);? // 輸出 Student [name=張三, age=13]
? ? ? ? ? ? ? ? change(s);
? ? ? ? ? ? ? ? System.out.println(s);? // 3:請問輸出什么?
? ? ? ? ? ? ? ? change1(s);
? ? ? ? ? ? ? ? System.out.println(s);? // 4:請問輸出什么?
? ? ? ? }
? ? ? ? public static void change(String s) {
? ? ? ? ? ? ? ? s = s+"def";
? ? ? ? }
? ? ? ? public static void change(int a) {
? ? ? ? ? ? ? ? a = a + 10;
? ? ? ? }
? ? ? ? public static void change(Student s) {
? ? ? ? ? ? ? ? s = new Student("李四",14);
? ? ? ? }
? ? ? ? public static void change1(Student s) {
? ? ? ? ? ? ? ? s.setName("李四");
? ? ? ? ? ? ? ? s.setAge(14);
? ? ? ? }
}
大家看完上面的題目之后摩泪,估計(jì)有很多同學(xué)能回答出前兩問, 1:輸出10, 2:輸出abc劫谅,??因?yàn)檫@類的參數(shù)傳遞在咱們java基礎(chǔ)課程的第5天和第13天都有講到见坑。 但是雖然講了,但是有很多同學(xué)都沒有充分的理解透徹捏检,這也就是為什么大家回答不出 第三問 和 第四問 的原因荞驴。實(shí)際上第三問的答案是 3:輸出Student [name=張三, age=13] 4:Student [name=李四, age=14]。 下面我就給大家講解一下贯城。
? ?? ?首先用一句話來歸納java中參數(shù)傳遞:不管是基本類型還是引用類型: 形式參數(shù)做賦值操作的時(shí)候熊楼,實(shí)際參數(shù)不發(fā)生改變,如果在方法里面是改變形式參數(shù)內(nèi)部的一些東西的時(shí)候 那么實(shí)際參數(shù)發(fā)生改變能犯。?1.??不管是基本類型還是引用類型: 形式參數(shù)做賦值操作的時(shí)候鲫骗,實(shí)際參數(shù)不發(fā)生改變
? ?? ???(當(dāng)被調(diào)用的方法開始執(zhí)行的時(shí)候,就從方法區(qū)里面把方法拿到了棧內(nèi)存中踩晶, 形式參數(shù)變量也根據(jù)傳遞過
? ?? ?? ?去的值進(jìn)行初始化执泰,當(dāng)方法用完了, 那么該方法在棧內(nèi)存中的變量也消失了渡蜻。在所以也就是只在棧內(nèi)存
? ?? ?? ?中對方法里面變量進(jìn)行了改變术吝,是不影響實(shí)際參數(shù)的。而加減乘除、賦值[就算是引用類型之間的賦值顿苇,是
? ?? ?? ?不是也只是在棧內(nèi)存中把地址值進(jìn)行的賦值]這一系列的賦值操作都是在棧內(nèi)存中對方法里面變量進(jìn)行了改
? ?? ?? ?變峭咒,而方法執(zhí)行完畢后 從棧內(nèi)存中消失了,回到了調(diào)用這個方法 的 main方法棧內(nèi)存中纪岁,實(shí)際參數(shù)原來是
什么 現(xiàn)在依然是什么)
2.??如果在方法里面是改變形式參數(shù)內(nèi)部的一些東西的時(shí)候 那么實(shí)際參數(shù)發(fā)生改變
(對于引用類型凑队,它隨著參數(shù)傳遞到方法里面去的是地址值,指向的是堆中的對象幔翰,如果在方法里面通過
? ?? ???這個地址值改變對象內(nèi)部的一些屬性漩氨,即使方法用完了,方法里面的變量的地址值的指向也消失了遗增,但是
? ?? ???對象內(nèi)部的一些屬性還是已經(jīng)改變了叫惊,這些屬性不會消失[因?yàn)樵诙褍?nèi)存中],所以實(shí)際參數(shù)還是會改變做修。如
? ?? ???果是基本類型霍狰,根本在堆內(nèi)存中沒有指向,基本類型都在棧內(nèi)存或者常量池[值更不能被改變]中饰及,所以基本
類型形式參數(shù)的改變無論如何是改變不了實(shí)際參數(shù)的)
3.?看完上面的兩句話和解釋蔗坯,相信大家還是覺得比較抽象,下面我給大家準(zhǔn)備了一個代碼案例燎含,每一行代碼都有對應(yīng)的解釋宾濒,看完下面的案例后估計(jì)大家就會真正的明白java中參數(shù)傳遞,參數(shù)改變時(shí)機(jī)的問題了
public class Demo2 {
????public static void main(String[] args) {
? ? ? ? ? ? ? ? int a? = 10;
? ? ? ? ? ? ? ? int b = 20;
? ? ? ? ? ? ? ? System.out.println(a+"? "+b);//10? 20
? ? ? ? ? ? ? ? change1(a,b);
? ? ? ? ? ? ? ? //形式參數(shù)做賦值操作的時(shí)候屏箍,實(shí)際參數(shù)不發(fā)生改變
? ? ? ? ? ? ? ? //基本類型一般都在棧內(nèi)存中(所以 堆內(nèi)存中沒有指向 內(nèi)部也就沒有東西嘛)绘梦,
? ? ? ? ? ? ? ? //所以值能做一些加減乘除、賦值的操作赴魁,
? ? ? ? ? ? ? ? //而做完了這些操作卸奉,就在占內(nèi)存中消失了,所以不會影響實(shí)際參數(shù)
? ? ? ? ? ? ? ? System.out.println(a+"? "+b);//10? 20
? ? ? ? ? ? ? ? System.out.println("-------------------");
? ? ? ? ? ? ? ? Student s = new Student();
? ? ? ? ? ? ? ? System.out.println(s);//Student [name=null, age=0]
? ? ? ? ? ? ? ? change2(s);//詳見方法內(nèi)部注釋
? ? ? ? ? ? ? ? //如果在方法里面是改變形式參數(shù)內(nèi)部的一些東西的時(shí)候 那么實(shí)際參數(shù)發(fā)生改變
? ? ? ? ? ? ? ? System.out.println(s);//Student [name=hehe, age=1]
? ? ? ? ? ? ? ? System.out.println("-------------------");
? ? ? ? ? ? ? ? String string = "abc";
? ? ? ? ? ? ? ? System.out.println(string);//abc
? ? ? ? ? ? ? ? change3(string);//詳見方法內(nèi)部注釋
? ? ? ? ? ? ? ? //形式參數(shù)做賦值操作的時(shí)候尚粘,實(shí)際參數(shù)不發(fā)生改變
? ? ? ? ? ? ? ? System.out.println(string);//abc
? ? ? ? ? ? ? ? System.out.println("-------------------");
? ? ? ? ? ? ? ? StringBuffer sb = new StringBuffer("hello");
? ? ? ? ? ? ? ? System.out.println(sb);//hello
? ? ? ? ? ? ? ? change4(sb);//詳見方法內(nèi)部注釋
? ? ? ? ? ? ? ? //如果在方法里面是改變形式參數(shù)內(nèi)部的一些東西的時(shí)候 那么實(shí)際參數(shù)發(fā)生改變
? ? ? ? ? ? ? ? System.out.println(sb);//helloworld
? ? ? ? ? ? ? ? System.out.println("-------------------");
? ? ? ? ? ? ? ? int[] arr ={1,2,5,8,4,3};
? ? ? ? ? ? ? ? System.out.println(Arrays.toString(arr));//[1, 2, 5, 8, 4, 3]
? ? ? ? ? ? ? ? change5(arr,0,1);//詳見方法內(nèi)部注釋
? ? ? ? ? ? ? ? //如果在方法里面是改變形式參數(shù)內(nèi)部的一些東西的時(shí)候 那么實(shí)際參數(shù)發(fā)生改變
? ? ? ? ? ? ? ? System.out.println(Arrays.toString(arr));//[2, 1, 5, 8, 4, 3]
? ? ? ? ? ? ? ? Arrays.sort(arr);
? ? ? ? ? ? ? ? System.out.println(Arrays.toString(arr));//[1, 2, 3, 4, 5, 8]
? ? ? ? ? ? ? ? System.out.println("-------------------");
? ? ? ? ? ? ? ? StringBuffer sb1 = new StringBuffer("abcd");
? ? ? ? ? ? ? ? StringBuffer sb2 = new StringBuffer("efgh");
? ? ? ? ? ? ? ? change6(sb1,sb2);//詳見方法內(nèi)部注釋
? ? ? ? ? ? ? ? System.out.println(sb1);//abcd
? ? ? ? ? ? ? ? //形式參數(shù)做賦值操作的時(shí)候择卦,實(shí)際參數(shù)不發(fā)生改變
? ? ? ? ? ? ? ? System.out.println("-------------------");
? ? ? ? ? ? ? ? Student s1 = new Student("hehe",1);
? ? ? ? ? ? ? ? Student s2 = new Student("haha",20);
? ? ? ? ? ? ? ? change7(s1,s2);//詳見方法內(nèi)部注釋
? ? ? ? ? ? ? ? //形式參數(shù)做賦值操作的時(shí)候,實(shí)際參數(shù)不發(fā)生改變
? ? ? ? ? ? ? ? System.out.println(s1);//Student [name=hehe, age=1]
? ? ? ? }
? ? ? ? private static void change7(Student s1, Student s2) {
? ? ? ? ? ? ? ? //引用類型s1指向的是一個地址值郎嫁,s2也是指向的地址值秉继,那么把s2的地址值賦給了s1,這時(shí)候s1指向的地址
? ? ? ? ? ? ? ? //值改變了泽铛,而s1內(nèi)部(堆內(nèi)存)的東西改變了嗎尚辑?沒有啊 ,等這個方法調(diào)用完畢了盔腔,地址值的指向也都消失了杠茬,
? ? ? ? ? ? ? ? //s1還是指向原來的地址值月褥,原來的地址值內(nèi)部(堆內(nèi)存)的東西還是沒有改變,所以 賦值操作不會影響實(shí)際參數(shù)
? ? ? ? ? ? ? ? s1=s2;
? ? ? ? }
? ? ? ? private static void change6(StringBuffer sb1, StringBuffer sb2) {
? ? ? ? ? ? ? ? //引用類型sb1指向的是一個地址值瓢喉,sb2也是指向的地址值宁赤,那么把sb2的地址值賦給了sb1,這時(shí)候sb1指向的地址
? ? ? ? ? ? ? ? //值改變了栓票,而sb1內(nèi)部(堆內(nèi)存)的東西改變了嗎决左?沒有啊 ,等這個方法調(diào)用完畢了走贪,地址值的指向也都消失了佛猛,
? ? ? ? ? ? ? ? //sb1還是指向原來的地址值,原來的地址值內(nèi)部(堆內(nèi)存)的東西還是沒有改變坠狡,所以 賦值操作不會影響實(shí)際參數(shù)
? ? ? ? ? ? ? ? sb1=sb2;
? ? ? ? }
? ? ? ? private static void change5(int[] arr, int i, int j) {
? ? ? ? ? ? ? ? //引用類型arr指向的其實(shí)是一個地址值继找,那么通過地址值將對象內(nèi)部(堆內(nèi)存)的值發(fā)生改變了,
? ? ? ? ? ? ? ? //即使這個方法調(diào)用完畢了逃沿,s所代表的地址的指向消失了婴渡,那么對象的內(nèi)部其實(shí)已經(jīng)改變了,所以形式參數(shù)改變實(shí)際參數(shù)
? ? ? ? ? ? ? ? int temp = arr[i];
? ? ? ? ? ? ? ? arr = arr[j];
? ? ? ? ? ? ? ? ?arr[j] = temp;
? ? ? ? }
? ? ? ? ? private static void change4(StringBuffer sb) {
? ? ? ? ? ? ? ? ?//引用類型sb指向的其實(shí)是一個地址值感挥,那么通過地址值將對象內(nèi)部(堆內(nèi)存)的字符長度改變了缩搅,?
? ? ? ? ? ? ? ? ?//即使這個方法調(diào)用完畢了,s所代表的地址的指向消失了触幼,那么對象的內(nèi)部其實(shí)已經(jīng)改變了,所以形式參數(shù)改變實(shí)際參數(shù)?
? ? ? ? ? ? ? ? ?sb.append("world");?
? ? ? ? ?}?
? ? ? ? ?private static void change3(String string) {?
? ? ? ? ? ? ? ? //String也是一個引用類型究飞,但是String的值是放在了常量池中置谦,而且常量池中的值是不能被改變的?
? ? ? ? ? ? ? ? //在方法里面這個string所代表的是常量池中值得地址值,那么我說string += "def"這句話在常量池中其實(shí)是這樣的:“找有沒有abcdef亿傅,如果有就把a(bǔ)bcdef的地址值賦給string?
? ? ? ? ? ? ? ? ?//如果沒有就在常量池中創(chuàng)建一個abcdef 并把地址值賦給string”媒峡。 然而當(dāng)我方法用完了 string代表的地址值的指向也消失了,那么原來main方法中的string也不發(fā)生改變?
? ? ? ? ? ? ? ? string += "def";?
? ? ? ? ?}[
? ? ? ? private static void change2(Student s) {?
? ? ? ? ? ? ? ? ?//引用類型s指向的其實(shí)是一個地址值葵擎,那么通過地址值將對象內(nèi)部(堆內(nèi)存)的屬性改變了谅阿,
? ? ? ? ? ? ? ? //即使這個方法調(diào)用完畢了,s所代表的地址的指向消失了酬滤,那么對象的內(nèi)部其實(shí)已經(jīng)改變了签餐,所以形式參數(shù)改變實(shí)際參數(shù)
? ? ? ? ? ? ? ? ?s.setName("hehe");
? ? ? ? ? ? ? ? ?s.setAge(1);
? ? ? ? ?}
? ? ? ? ? private static void change1(int a, int b) {
? ? ? ? ? ? ? ? ? int temp = a;
? ? ? ? ? ? ? ? ? a= b;
? ? ? ? ? ? ? ? ? b=temp;
? ? ? ? ? }
? }