Java方法调用的参数传递
首先给结论:Java中均为值传递。
下面通过概念分析+代码示例的方式,实现深刻理解值传递的含义,避免死记硬背。
Java的两种数据类型
- 基本数据类型,比如int,double,boolean等,是从C语言中保留的类型。比如 int num = 10;在堆内存中存储结构如下:
- 引用数据类型,比如Object类、及其子类,String类等。即使用Class定义的类。
比如 String str = "hello"; 在堆内存中存储结构如下:
引用数据类型类似C中的指针。以C语言的代码来看,等价表达式为:p = "hello"。而方法调用时,传递的参数值为p,而非p;
代码示例
java
public class Test {
public String s;
Test(String s){
this.s = s;
}
public void setS(String s, Test test){
test.s = s;
}
public void setNewS(String s, Test test){
test = new Test(test.s);
test.setS(s);
System.out.println("setNewS:"+test.toString());
}
@Override
public String toString(){
return "s: " + this.s;
}
public static void main(String[] args) {
Test test = new Test("1");
/** 步骤1:打印结果为:s: 1 **/
System.out.println(test.toString());
test.setS("2");
/** 步骤2:打印结果为: s: 2 **/
System.out.println(test.toString());
test.setNewS("3",test);
/** 步骤3:打印结果为:s: 2 **/
System.out.println(test.toString());
}
}
步骤1中打印的结果是初始值1;
步骤2,调用setS("2",test),将test实例的属性s修改为2;
步骤3,调用setNewS("3",test),test的属性为何仍旧是2呢?
原因:setNewS方法中new 了一个新对象,赋值给引用test;通过内存图像表达:
使用new 在内存中创建了一个新Test对象,后续的修改基于这个新对象,原有的对象没有任何变化,仍旧由main方法中的test引用指向着。而setNewS方法中的test引用在该方法执行后,就被清理。
关键点
我们只看被调用方法内部:
理解的关键就是看方法中有没有调用new方法创建新的对象,并且将test引用指向新的对象。
如果这样做了,那么在方法内部对test引用的任何修改都将在新对象上生效。而和老对象无关。
如果没有这么做,那么方法内部对test引用的任何修改都会在老对象生效,那么main方法中再去打印该老对象的信息自然就发生变化了。
关于基本数据类型作为参数
基本数据类型作为参数传递时,传的就是值。
比如 int i = 0; add(i)和add(0的含义是一样的。因为基本数据类型没有引用一说,只有字面量,i代表的就是0;
比如
java
void add(int i){
//方法内部的i是JVM新创建局部变量
i = i + 1;
}
//方法外部的i是全局变量,不会因为add被改变
int i = 1;
add(i);
后续打印i的值仍旧为1,而不是2;
所以我们在add中对i的任何修改都不可能改变外层 i 的值;