一、纠正
纠正一些错误理解:
- 错误理解一:值传递和引用传递,区别是传递的内容,如果是个值,就是值传递,如果是引用,就是引用传递
- 错误理解二:Java是引用传递
- 错误理解三:传递的类型如果是普通类型,就是值传递,如果是对象,就是引用传递。
二、形参和实参
形式参数:
在定义函数名和函数体的时候使用的参数,用来接收调用该函数时传入的参数
实际参数:
在调用有参函数时,由于调用的函数有参,主函数与被调函数之间有数据的传递,在主函数调用一个函数时,函数名括号内中填入的参数就为“实际参数”
举例:
public class DemoApplication {
public static void main(String[] args) {
DemoApplication demoApplication = new DemoApplication();
demoApplication.user("甲"); //甲为实参
}
public void user(String name){ //(String name)中的name为形参
System.out.println(name);
}
}
形式参数相当于使用有参函数时为后面要传入的实际参数开辟的空间,而实际参数是调用有参方法时真正传递的内容
三、值传递和引用传递
我们在调用一个有参函数时,会在进行函数调用时把实际参数传递给形式参数,这个传递的过程分为了两种情况,值传递和引用传递
值传递:
在调用函数时将实际参数复制一份传递到函数中,这样函数中如果对参数进行修改,将不会影响到实际参数
引用传递:
在调用函数时将实际参数的地址直接传递到函数中,那么函数中对参数的修改,将直接影响到实际的参数
根据代码判断java中到底是值传递还是引用传递
public class DemoApplication {
public static void main(String[] args) {
DemoApplication demoApplication = new DemoApplication();
int i = 10;
demoApplication.pass(i);
System.out.println("print in main, i is " + i);
}
public void pass(int j){ //(String name)中的name为形参
j = 20;
System.out.println("print in pass, j is " + j);
}
}
控制台打印输出结果为:
print in pass, j is 20
print in main, i is 10
- 按照顺序执行main方法,在main方法中,我们先是给 赋值 i 为10,然后调用pass方法
- 我们在pass方法中对所需要传入的实参进行了修改,即 j = 20(在pass方法中修改参数)
- 但打印输出的结果仍为 i = 10;说明在方法体中对实际参数修改并不会改变实际参数的值
以上就能得出Java是值传递吗,并不是,看以下例子:
先封装一个 User类,属性为name和gender
public class User {
private String name;
private String gender;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
在启动类中,定义一个pass方法,传入整个User类作为形参,new一个user对象,通过setName和setGender进行属性的赋值
public class DemoApplication {
public static void main(String[] args) {
DemoApplication demoApplication = new DemoApplication();
User userOther = new User();
userOther.setName("乙");
userOther.setGender("男");
demoApplication.pass(userOther);
System.out.println("print in main, userOtherName is " + userOther.getName());
System.out.println("print in main, userOtherGender is " + userOther.getGender());
}
public void pass(User user){
user.setName("甲");
System.out.println("print in pass, userName is " + user.getName());
System.out.println("print in pass, userGender is " + user.getGender());
}
}
控制台打印输出的结果为:
print in pass, userName is 甲
print in pass, userGender is 男
print in main, userOtherName is 甲
print in main, userOtherGender is 男
- 按照顺序执行main方法,先new一个userOther对象,利用setName和getName给属性赋值,
- 再调用pass方法,但是pass方法中也通过setName对传入的name实参进行了修改(在pass方法中修改参数)
- 根据最终打印结果可以看到,在main方法中,实参的值由于执行方法时在方法体中做了修改,实参由原来的“乙”变成了“甲”,也就是说实参发生了改变
- pass方法中pass(User user)是将整个对象作为参数传递
有人因此得出结论:传递
普通类型
的参数时是值传递,传递
对象类型
的时候是引用传递。这种说法仍然是不正确的,
-
普通类型:byte(位)、short(短整数)、int(整数)、long(长整数)、float(单精度)、double(双精度)、char(字符)和boolean(布尔值)。
-
对象类型:包括String 在内的对象属性类型(String name)或者整个对象的类型(User user)
举个例子:下面进行参数类型为对象的参数传递(String 类型)
public class DemoApplication {
public static void main(String[] args) {
DemoApplication demoApplication = new DemoApplication();
String name = "B";
demoApplication.pass(name);
System.out.println("print in main, name is " + name);
}
public void pass(String name){
name = "A";
System.out.println("print in pass, Name is " + name);
}
}
控制台输出结果为:
print in pass, Name is A
print in main, name is B
结论:由此可见,八大基本类型和String作为参数进行传递时不会改变值,传递的只是副本,并不会对原来的值进行改变,
第一个例子:下面进行参数类型为对象的参数传递(除了String类型其他类型)
import java.util.Arrays;
public class DemoApplication {
public static void main(String[] args) {
int[] a = new int[] {1,2,3,4};
change(a);
System.out.println("print in main, a is " + Arrays.toString(a));
}
public static void change(int[] a){
a[0] =7;
System.out.println("print in pass, a is " + Arrays.toString(a));
}
}
控制台打印输出的内容为:
print in pass, a is [7, 2, 3, 4]
print in main, a is [7, 2, 3, 4]
对象类型作为参数传递时改变了原来的值。
第二个例子:注意与下面这个例子的区分:’
import java.util.Arrays;
public class DemoApplication {
public static void main(String[] args) {
int[] a = new int[] {1,2,3,4};
change(a);
System.out.println("print in main, a is " + Arrays.toString(a));
}
public static void change(int[] a){
a = new int[] {5,6,7};
System.out.println("print in pass, a is " + Arrays.toString(a));
}
}
控制台打印输出:
print in pass, a is [5, 6, 7]
print in main, a is [1, 2, 3, 4]
根据控制台的输出内容可以看到,打印输出的内容并没有发生变化
- 当一个对象实例(这里指的a),作为参数被传递到方法中change(a),参数的值就是该对象引用的一个副本,指向同一个对象,对象的内容可以在调用的方法中进行更改(第一个例子),
-
如果在函数对
传递过来的对象参数进行new或者赋值给另外一个对象
(第二个例子中的a = new int[] {5,6,7};),这就是在函数中改变了副本的地址,那么这个参数的改变时不会传递到实参的。所以第二个例子的输出仍为原来。 -
传递过来的对象参数进行new或者赋值给另外一个对象这句话就相当于开辟了一个新的地址来存放值,与上面的实参没有关系了
四、值传递和引用传递的区别