小瓜瓜做爲一個Java初學者,今天跟我說她想經過一個Java方法,將外部變量經過參數傳遞到方法中去,進行邏輯處理,方法執行完畢以後,再對修改過的變量進行判斷處理,代碼以下所示。java
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(); } }
上述代碼是有問題的,布爾變量a和整型變量b在方法操做以後,它們的值並無發生變化,小瓜瓜事與願違。ide
在Java方法中參數列表有兩種類型的參數,基本類型和引用類型。this
基本類型:值存放在局部變量表中,不管如何修改只會修改當前棧幀的值,方法執行結束對方法外不會作任何改變;此時須要改變外層的變量,必須返回主動賦值。spa
引用數據類型:指針存放在局部變量表中,調用方法的時候,副本引用壓棧,賦值僅改變副本的引用。可是若是經過操做副本引用的值,修改了引用地址的對象,此時方法之外的引用此地址對象固然被修改。(兩個引用,同一個地址,任何修改行爲2個引用同時生效)。.net
這兩種類型都是將外面的參數變量拷貝一份到局部變量中,基本類型爲值拷貝,引用類型就是將引用地址拷貝一份。3d
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); } }
返回結果指針
a : false b : 5 a : false b : 5
1. 方法參數flg被初始化爲外部變量a的拷貝,值爲false。參數num被初始化爲外部變量b的拷貝,值爲5。對象
2. 執行方法邏輯,方法中的局部變量flg被改變爲true,局部變量flg被改變爲10。blog
3.方法執行完畢,再也不局部變量再也不被使用到,等待被GC回收。get
結論:當方法參數爲基本類型時,是將外部變量值拷貝到局部變量中而進行邏輯處理的,故方法是不能修改原基本變量的。
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); } }
結果爲
a : false b : 5 a : false b : 5
當傳入參數爲包裝類型時,爲對象的引用地址拷貝。那麼既然是引用拷貝爲何仍是沒有更改原來的包裝類型的變量值呢?
這是由於Java中的自動裝箱機制,當在方法中執行 flg = true 時,實際在編譯後執行的是 flg = Boolean.valueOf(true),即又會產生一個新的Boolean對象。同理Integer num也是如此。
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); } }
結果爲
ParamObject{flg=false, num=5} ParamObject{flg=true, num=10}
結論:對於引用類型的方法參數,會將外部變量的引用地址,複製一份到方法的局部變量中,兩個地址指向同一個對象。因此若是經過操做副本引用的值,修改了引用地址的對象,此時方法之外的引用此地址對象也會被修改。(兩個引用,同一個地址,任何修改行爲2個引用同時生效)。
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); } }
結果爲
a : ParamObject{flg=true, num=1} b : ParamObject{flg=false, num=2} a : ParamObject{flg=true, num=1} b : ParamObject{flg=false, num=2}
有了上面的知識以後,咱們會發現這個方法中的引用地址交換,只不過是一個把戲而已,只是對方法中的兩個局部變量的對象引用值進行了交換,不會對原變量引用產生任何影響的。
Java方法中只能Return一個返回值,那麼如何在一個方法中返回兩個或者多個返回值呢?咱們能夠經過使用泛型來定義一個二元組來達到咱們的目的。
public class TwoTuple<A, B> { 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 TwoTuple<Boolean, Integer> returnTwoResult(Boolean flg, Integer num) { flg = true; num = 10; return new TwoTuple<>(flg, num); } public static void main(String[] args) { TwoTuple<Boolean,Integer> result = returnTwoResult(false,5); System.out.println("first : " + result.first + ", second : " + result.second); } }
package com.lingyejun.authenticator; 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"); } } /** * 基本類型,賦值運算=,會直接改變變量的值,原來的值被覆蓋掉 * 引用類型,複製運算=,會改變引用中所保存的地址,舊地址被覆蓋掉,但原來的對象不會改變。 * * @param flg * @param num */ 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 TwoTuple<Boolean, Integer> returnTwoResult(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<Boolean,Integer> result = returnTwoResult(false,5); System.out.println("first : " + result.first + ", second : " + result.second); } }
參考文章:
https://blog.csdn.net/javazejian/article/details/51192130
http://www.javashuo.com/article/p-qhbzlcui-me.html