前言
之前一个同事面试遇到了这么一个面试题“Java方法的参数是值传递还是引用传递?”,给我看之后我也是对结果不太确定。所以就百度了一波,感觉虽然问题很简单,但是问题直戳本质,觉得很有必要留下一点点痕迹啦。
在Java方法中参数列表有两种类型的参数,基本类型和引用类型。
基本类型:值存放在局部变量表中,无论如何修改只会修改当前栈帧的值,方法执行结束对方法外不会做任何改变;此时需要改变外层的变量,必须返回主动赋值。
引用数据类型:指针存放在局部变量表中,调用方法的时候,副本引用压栈,赋值仅改变副本的引用。但是如果通过操作副本引用的值,修改了引用地址的对象,此时方法以外的引用此地址对象当然被修改。(两个引用,同一个地址,任何修改行为2个引用同时生效)。
方法参数为基本类型时
public class Test{
public static void test(boolean flg, int num) {
flg = true;
num = 5;
}
public static void main(String[] args) {
boolean a = false;
int b = 3;
System.out.println("a : " + a + " b : " + b);
test(a, b);
System.out.println("a : " + a + " b : " + b);
}
}
//结果
a : false b : 3
a : false b : 3
结论:当方法参数为基本类型时,jvm将外部变量也就是我们所说的参数的值拷贝到局部变量中而进行处理的,但是要注意此时是处理的是该局部变量的值,对原基本变量的并不产生什么效果。
方法参数为包装类型的引用类型
public class Test{
public static void test(boolean flg, int num) {
flg = true;//flg = Boolean.valueOf(true)
num = 5;
}
public static void main(String[] args) {
boolean a = false;
int b = 3;
System.out.println("a : " + a + " b : " + b);
test(a, b);
System.out.println("a : " + a + " b : " + b);
}
}
//结果
a : false b : 3
a : false b : 3
结论:当方法参数为引用类型是,传入的参数值为引用地址的拷贝,但是我们会发现那为啥没变化呢。看我上面的注解,因为java的自动装箱机制又产生了一个新的对象,所以也对于原变量并没有发生变化。
方法参数为类的对象引用
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 Test{
public static void test(ParamObject paramObject) {
paramObject.setFlg(true);
paramObject.setNum(10);
}
public static void main(String[] args) {
ParamObject a = new ParamObject(false, 5);
System.out.println(a);
test(a);
System.out.println(a);
}
}
//结果:
ParamObject{flg=false, num=5}
ParamObject{flg=true, num=10}
结论:对于引用类型的方法参数,会将外部变量的引用地址,复制一份到方法的局部变量中,两个地址指向同一个对象。所以如果通过操作副本引用的值,修改了引用地址的对象,此时方法以外的引用此地址对象也会被修改。(两个引用,同一个地址,任何修改行为2个引用同时生效)。
总结
基本类型:值存放在局部变量表中,在对参数修改时只会修改当前栈帧的值,方法执行结束候对方法外不会做任何改变;此时需要改变外层的变量,必须返回主动赋值。
引用数据类型:指针存放在局部变量表中,调用方法的时候,副本引用压栈,赋值仅改变副本的引用。但是如果通过操作副本引用的值,修改了引用地址的对象,此时方法以外的引用此地址对象当然被修改。(两个引用,同一个地址,任何修改行为2个引用同时生效)。
这两种类型都是将外面的参数变量拷贝一份到局部变量中,基本类型为值拷贝,引用类型就是将引用地址拷贝一份。
- 当方法参数为基本类型时为值传递。
- 当传入参数为包装类型时为引用传递,但是由于java的自动拆箱机制修改参数值并不会发生值改变
- 对于引用类型的方法参数为引用传递,修改参数值会发生值改变