摘要:引用數(shù)據(jù)類(lèi)型指針存放在局部變量表中,調(diào)用方法的時(shí)候,副本引用壓棧,賦值僅改變副本的引用。方法執(zhí)行完畢,不再局部變量不再被使用到,等待被回收。
小方法大門(mén)道
小瓜瓜作為一個(gè)Java初學(xué)者,今天跟我說(shuō)她想通過(guò)一個(gè)Java方法,將外部變量通過(guò)參數(shù)傳遞到方法中去,進(jìn)行邏輯處理,方法執(zhí)行完畢之后,再對(duì)修改過(guò)的變量進(jìn)行判斷處理,代碼如下所示。
public class MethodParamsPassValue { public static void doErrorHandle() { boolean a = false; int b = 5; passBaseValue(a, b); if (a == true || b == 10) { System.out.println("Execute Something"); } else { System.out.println("param result wrong"); } } public static void passBaseValue(boolean flg, int num) { flg = true; num = 10; } public static void main(String[] args) { doErrorHandle(); } }
上述代碼是有問(wèn)題的,布爾變量a和整型變量b在方法操作之后,它們的值并沒(méi)有發(fā)生變化,小瓜瓜事與愿違。
究其原因在Java方法中參數(shù)列表有兩種類(lèi)型的參數(shù),基本類(lèi)型和引用類(lèi)型。
基本類(lèi)型:值存放在局部變量表中,無(wú)論如何修改只會(huì)修改當(dāng)前棧幀的值,方法執(zhí)行結(jié)束對(duì)方法外不會(huì)做任何改變;此時(shí)需要改變外層的變量,必須返回主動(dòng)賦值。
引用數(shù)據(jù)類(lèi)型:指針存放在局部變量表中,調(diào)用方法的時(shí)候,副本引用壓棧,賦值僅改變副本的引用。但是如果通過(guò)操作副本引用的值,修改了引用地址的對(duì)象,此時(shí)方法以外的引用此地址對(duì)象當(dāng)然被修改。(兩個(gè)引用,同一個(gè)地址,任何修改行為2個(gè)引用同時(shí)生效)。
這兩種類(lèi)型都是將外面的參數(shù)變量拷貝一份到局部變量中,基本類(lèi)型為值拷貝,引用類(lèi)型就是將引用地址拷貝一份。
方法參數(shù)為基本類(lèi)型的值傳遞public class MethodParamsPassValue { public static void passBaseValue(boolean flg, int num) { flg = true; num = 10; } public static void main(String[] args) { boolean a = false; int b = 5; System.out.println("a : " + a + " b : " + b); passBaseValue(a, b); System.out.println("a : " + a + " b : " + b); } }
返回結(jié)果:
a : false b : 5 a : false b : 5
方法參數(shù)flg被初始化為外部變量a的拷貝,值為false。參數(shù)num被初始化為外部變量b的拷貝,值為5。
執(zhí)行方法邏輯,方法中的局部變量flg被改變?yōu)閠rue,局部變量flg被改變?yōu)?0。
3.方法執(zhí)行完畢,不再局部變量不再被使用到,等待被GC回收。
結(jié)論:當(dāng)方法參數(shù)為基本類(lèi)型時(shí),是將外部變量值拷貝到局部變量中而進(jìn)行邏輯處理的,故方法是不能修改原基本變量的。
方法參數(shù)為包裝類(lèi)型的引用傳遞public class MethodParamsPassValue { public static void passReferenceValue(Boolean flg, Integer num) { flg = true; num = 10; } public static void main(String[] args) { Boolean a = false; Integer b = 5; System.out.println("a : " + a + " b : " + b); passReferenceValue(a, b); System.out.println("a : " + a + " b : " + b); } }
結(jié)果為:
a : false b : 5 a : false b : 5
當(dāng)傳入?yún)?shù)為包裝類(lèi)型時(shí),為對(duì)象的引用地址拷貝。那么既然是引用拷貝為什么還是沒(méi)有更改原來(lái)的包裝類(lèi)型的變量值呢?
這是因?yàn)镴ava中的自動(dòng)裝箱機(jī)制,當(dāng)在方法中執(zhí)行 flg = true 時(shí),實(shí)際在編譯后執(zhí)行的是 flg = Boolean.valueOf(true),即又會(huì)產(chǎn)生一個(gè)新的Boolean對(duì)象。同理Integer num也是如此。
方法參數(shù)為類(lèi)的對(duì)象引用時(shí)public class ParamObject { private boolean flg; private int num; public ParamObject(boolean flg, int num) { this.flg = flg; this.num = num; } public boolean isFlg() { return flg; } public void setFlg(boolean flg) { this.flg = flg; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } @Override public String toString() { return "ParamObject{" + "flg=" + flg + ", num=" + num + "}"; } }
public class MethodParamsPassValue { public static void passObjectValue(ParamObject paramObject) { paramObject.setFlg(true); paramObject.setNum(10); } public static void main(String[] args) { ParamObject a = new ParamObject(false, 5); System.out.println(a); passObjectValue(a); System.out.println(a); } }
結(jié)果為:
ParamObject{flg=false, num=5} ParamObject{flg=true, num=10}
結(jié)論:對(duì)于引用類(lèi)型的方法參數(shù),會(huì)將外部變量的引用地址,復(fù)制一份到方法的局部變量中,兩個(gè)地址指向同一個(gè)對(duì)象。所以如果通過(guò)操作副本引用的值,修改了引用地址的對(duì)象,此時(shí)方法以外的引用此地址對(duì)象也會(huì)被修改。(兩個(gè)引用,同一個(gè)地址,任何修改行為2個(gè)引用同時(shí)生效)。
腦筋急轉(zhuǎn)彎之"交換兩個(gè)對(duì)象"public class MethodParamsPassValue { public static void swapObjectReference(ParamObject object1, ParamObject object2) { ParamObject temp = object1; object1 = object2; object2 = temp; } public static void main(String[] args) { ParamObject a = new ParamObject(true, 1); ParamObject b = new ParamObject(false, 2); System.out.println("a : " + a + " b : " + b); swapObjectReference(a, b); System.out.println("a : " + a + " b : " + b); } }
結(jié)果為
a : ParamObject{flg=true, num=1} b : ParamObject{flg=false, num=2} a : ParamObject{flg=true, num=1} b : ParamObject{flg=false, num=2}
有了上面的知識(shí)之后,我們會(huì)發(fā)現(xiàn)這個(gè)方法中的引用地址交換,只不過(guò)是一個(gè)把戲而已,只是對(duì)方法中的兩個(gè)局部變量的對(duì)象引用值進(jìn)行了交換,不會(huì)對(duì)原變量引用產(chǎn)生任何影響的。
一個(gè)方法返回兩個(gè)返回值Java方法中只能Return一個(gè)返回值,那么如何在一個(gè)方法中返回兩個(gè)或者多個(gè)返回值呢?(⊙v⊙)嗯,我們可以通過(guò)使用泛型來(lái)定義一個(gè)二元組來(lái)達(dá)到我們的目的。
public class TwoTuple { public final A first; public final B second; public TwoTuple(A a, B b) { first = a; second = b; } public String toString() { return "(" + first + ", " + second + ")"; } }
public class MethodParamsPassValue { public static TwoTuplereturnTwoResult(Boolean flg, Integer num) { flg = true; num = 10; return new TwoTuple<>(flg, num); } public static void main(String[] args) { TwoTuple result = returnTwoResult(false,5); System.out.println("first : " + result.first + ", second : " + result.second); } }
結(jié)果為:
first : true, second : 10完整代碼
package com.lingyejun.authenticator; /** * 基本類(lèi)型,賦值運(yùn)算=,會(huì)直接改變變量的值,原來(lái)的值被覆蓋掉。 * 引用類(lèi)型,賦值運(yùn)算=,會(huì)改變引用中所保存的地址,舊地址被覆蓋掉,但原來(lái)的對(duì)象不會(huì)改變。 * * @Author: lingyejun * @Date: 2019/6/16 * @Describe: * @Modified By: */ public class MethodParamsPassValue { public static void doErrorHandle() { boolean a = false; int b = 5; passBaseValue(a, b); if (a == true || b == 10) { System.out.println("Execute Something"); } else { System.out.println("param result wrong"); } } public static void passBaseValue(boolean flg, int num) { flg = true; num = 10; } public static void passReferenceValue(Boolean flg, Integer num) { flg = true; num = 10; } public static void passObjectValue(ParamObject paramObject) { paramObject.setFlg(true); paramObject.setNum(10); } public static void swapObjectReference(ParamObject object1, ParamObject object2) { ParamObject temp = object1; object1 = object2; object2 = temp; } public static TwoTuplereturnTwoResult(Boolean flg, Integer num) { flg = true; num = 10; return new TwoTuple<>(flg, num); } public static void main(String[] args) { doErrorHandle(); System.out.println("============================"); boolean initFlg = false; int initNum = 5; System.out.println("init flg : " + initFlg + " init num : " + initNum); passBaseValue(initFlg, initNum); System.out.println("init flg : " + initFlg + " init num : " + initNum); System.out.println("============================"); Boolean referenceFlg = false; Integer referenceNum = 5; System.out.println("reference flg : " + referenceFlg + " reference num : " + referenceNum); passReferenceValue(referenceFlg, referenceNum); System.out.println("reference flg : " + referenceFlg + " reference num : " + referenceNum); System.out.println("============================"); ParamObject paramObject = new ParamObject(false, 5); System.out.println(paramObject); passObjectValue(paramObject); System.out.println(paramObject); System.out.println("============================"); ParamObject object1 = new ParamObject(true, 1); ParamObject object2 = new ParamObject(false, 2); System.out.println("object1 : " + object1 + " object2 : " + object2); swapObjectReference(object1, object2); System.out.println("object1 : " + object1 + " object2 : " + object2); System.out.println("============================"); TwoTuple result = returnTwoResult(false,5); System.out.println("first : " + result.first + ", second : " + result.second); } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/77780.html
摘要:內(nèi)置函數(shù)們能夠被提拔出來(lái),這就意味著它們皆有獨(dú)到之處,有用武之地。因此,掌握內(nèi)置函數(shù)的用法,就成了我們應(yīng)該點(diǎn)亮的技能。報(bào)錯(cuò)包含了內(nèi)置命名空間中的名稱(chēng),在控制臺(tái)中輸入,就能發(fā)現(xiàn)很多內(nèi)置函數(shù)異常和其它屬性的名稱(chēng)。 Python 提供了很多內(nèi)置的工具函數(shù)(Built-in Functions),在最新的 Python 3 官方文檔中,它列出了 69 個(gè)。 大部分函數(shù)是我們經(jīng)常使用的,例如 p...
摘要:有種流行的觀點(diǎn)說(shuō)的另外一個(gè)特殊之處在于,在方法調(diào)用傳參數(shù)時(shí),是按值傳遞的,其他普通對(duì)象是引用傳遞。然而這種說(shuō)法是大大錯(cuò)誤的,至少是完全誤解了值傳遞和引用傳遞的概念。方法調(diào)用傳參只有一種傳遞就是值傳遞。 上篇文章說(shuō)到Java的String是比較特殊的對(duì)象,它是不可變的。 有種流行的觀點(diǎn)說(shuō)String的另外一個(gè)特殊之處在于,在方法調(diào)用傳參數(shù)時(shí),String是按值傳遞的,其他普通對(duì)象是引用傳...
摘要:接下了,我們調(diào)用方法,來(lái)嘗試改變的值以此驗(yàn)證中的傳值方式。我們將作為實(shí)參傳給方法,形參來(lái)接受這個(gè)實(shí)參,在這里就體現(xiàn)出了兩種傳參方式的不同。中只有值傳遞這一種方式,只不過(guò)對(duì)于引用類(lèi)型來(lái)說(shuō),傳遞的參數(shù)是對(duì)象的引用罷了。 前言 這幾天在整理java基礎(chǔ)知識(shí)方面的內(nèi)容,對(duì)于值傳遞還不是特別理解,于是查閱了一些資料和網(wǎng)上相關(guān)博客,自己進(jìn)行了歸納總結(jié),最后將其整理成了一篇博客。 值傳遞 值傳遞是指...
摘要:每個(gè)棧幀中包括局部變量表用來(lái)存儲(chǔ)方法中的局部變量非靜態(tài)變量函數(shù)形參。操作數(shù)棧虛擬機(jī)的解釋執(zhí)行引擎被稱(chēng)為基于棧的執(zhí)行引擎,其中所指的棧就是指操作數(shù)棧。指向運(yùn)行時(shí)常量池的引用存儲(chǔ)程序執(zhí)行時(shí)可能用到常量的引用。 本篇文章轉(zhuǎn)自微信公眾號(hào):Java后端技術(shù) 學(xué)過(guò)Java基礎(chǔ)的人都知道:值傳遞和引用傳遞是初次接觸Java時(shí)的一個(gè)難點(diǎn),有時(shí)候記得了語(yǔ)法卻記不得怎么實(shí)際運(yùn)用,有時(shí)候會(huì)的了運(yùn)用卻解釋不出...
摘要:操作數(shù)棧虛擬機(jī)的解釋執(zhí)行引擎被稱(chēng)為基于棧的執(zhí)行引擎,其中所指的棧就是指操作數(shù)棧?;緮?shù)據(jù)類(lèi)型的靜態(tài)變量前面提到方法區(qū)用來(lái)存儲(chǔ)一些共享數(shù)據(jù),因此基本數(shù)據(jù)類(lèi)型的靜態(tài)變量名以及值存儲(chǔ)于方法區(qū)的運(yùn)行時(shí)常 本文旨在用最通俗的語(yǔ)言講述最枯燥的基本知識(shí) 學(xué)過(guò)Java基礎(chǔ)的人都知道:值傳遞和引用傳遞是初次接觸Java時(shí)的一個(gè)難點(diǎn),有時(shí)候記得了語(yǔ)法卻記不得怎么實(shí)際運(yùn)用,有時(shí)候會(huì)的了運(yùn)用卻解釋不出原理,而...
閱讀 3966·2021-11-17 09:33
閱讀 1268·2021-10-09 09:44
閱讀 458·2019-08-30 13:59
閱讀 3565·2019-08-30 11:26
閱讀 2238·2019-08-29 16:56
閱讀 2914·2019-08-29 14:22
閱讀 3200·2019-08-29 12:11
閱讀 1344·2019-08-29 10:58