小瓜瓜做爲一個Java初學者,今天跟我說她想經過一個Java方法,將外部變量經過參數傳遞到方法中去,進行邏輯處理,方法執行完畢以後,再對修改過的變量進行判斷處理,代碼以下所示。bash
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方法中參數列表有兩種類型的參數,基本類型和引用類型。ui
基本類型:值存放在局部變量表中,不管如何修改只會修改當前棧幀的值,方法執行結束對方法外不會作任何改變;此時須要改變外層的變量,必須返回主動賦值。this
引用數據類型:指針存放在局部變量表中,調用方法的時候,副本引用壓棧,賦值僅改變副本的引用。可是若是經過操做副本引用的值,修改了引用地址的對象,此時方法之外的引用此地址對象固然被修改。(兩個引用,同一個地址,任何修改行爲2個引用同時生效)。spa
這兩種類型都是將外面的參數變量拷貝一份到局部變量中,基本類型爲值拷貝,引用類型就是將引用地址拷貝一份。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
複製代碼
方法參數flg被初始化爲外部變量a的拷貝,值爲false。參數num被初始化爲外部變量b的拷貝,值爲5。code
執行方法邏輯,方法中的局部變量flg被改變爲true,局部變量flg被改變爲10。cdn
3.方法執行完畢,再也不局部變量再也不被使用到,等待被GC回收。對象
結論:當方法參數爲基本類型時,是將外部變量值拷貝到局部變量中而進行邏輯處理的,故方法是不能修改原基本變量的。
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一個返回值,那麼如何在一個方法中返回兩個或者多個返回值呢?(⊙v⊙)嗯,咱們能夠經過使用泛型來定義一個二元組來達到咱們的目的。
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);
}
}
複製代碼
結果爲:
first : true, second : 10
複製代碼
package com.lingyejun.authenticator;
/**
* 基本類型,賦值運算=,會直接改變變量的值,原來的值被覆蓋掉。
* 引用類型,賦值運算=,會改變引用中所保存的地址,舊地址被覆蓋掉,但原來的對象不會改變。
*
* @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 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);
}
}
複製代碼