一、常见的错误认识
错误理解一:值传递和引用传递,区分的条件是传递的内容,如果是个值,就是值传递。如果是个引用,就是引用传递。
错误理解二:Java是引用传递。
错误理解三:传递的参数如果是普通类型,那就是值传递,如果是对象,那就是引用传递。
1.1、实参与形参是什么
形式参数:是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数。
实际参数:在调用有参函数时,主调函数和被调函数之间有数据传递关系。在主调函数中调用一个函数时,函数名后面括号中的参数称为“实际参数”。
简单举个例子:
public static void main(String[] args) {ParamTest pt = new ParamTest();pt.sout("Hello"); // 实际参数为 Hello}public void sout(String name) { // 形式参数为 nameSystem.out.println(name);}
实际参数是调用有参方法的时候真正传递的内容,而形式参数是用于接收实参内容的参数。
1.2、值传递与引用传递
上面提到了,当我们调用一个有参函数的时候,会把实际参数传递给形式参数。但是,在程序语言中,这个传递过程中有两种情况,即值传递和引用传递。我们来看下程序语言中是如何定义和区分值传递和引用传递的。
- 值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
- 引用传递(pass by reference)是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
值传递和引用传递的区别并不是传递的内容。而是实参到底有没有被复制一份给形参。在判断实参内容有没有受影响的时候,要看传的的是什么,如果你传递的是个地址,那么就看这个地址的变化会不会有影响,而不是看地址指向的对象的变化。
Java中其实还是值传递的,只不过对于对象参数,值的内容是对象的引用。
二、案例
1.1、int Demo
public class Main {public static void main(String[] args) {int i = 10;test(i);System.out.println(i==10); // true}static void test(int i) {i = 20;}}
1.2、String Demo
没有提供改变自身方法的引用类型
public class Main {public static void main(String[] args) {String str = "hello";test(str);System.out.println(str == "hello"); // true}static void test(String str) {str = "world";}}
1.3、StringBuilder Demo
提供了改变自身方法的引用类型
public class main {public static void main(String[] args) {StringBuilder sb = new StringBuilder("hello");test(sb);System.out.println(sb.toString() == "hello"); // falseSystem.out.println(sb.toString() == "hello world"); // falseSystem.out.println(sb.toString().equals("hello world")); // true}static void test(StringBuilder sb) {sb.append(" world");}}
1.4、StringBuilder Demo
提供了改变自身方法的引用类型,但是不使用,而是使用赋值运算符。
public class main {public static void main(String[] args) {StringBuilder sb = new StringBuilder("hello");test(sb);System.out.println(sb.toString() == "hello"); // falseSystem.out.println(sb.toString() == "world"); // falseSystem.out.println(sb.toString().equals("hello")); // true}static void test(StringBuilder sb) {sb = new StringBuilder("world");}}
1.5、StringBuilder Demo
试图在方法内将对象赋值为 null
public class Main {public static void main(String[] args) {StringBuilder sb = new StringBuilder("hello");test(sb);System.out.println(sb == null); // falseSystem.out.println(sb.toString().equals("hello")); // trueSystem.out.println(sb.toString() == "hello"); // falseString str = new String("hello");System.out.println(str == sb.toString()); // false}static void test(StringBuilder sb) {sb = null;}}
1.6、StringBuilder Demo
试图在方法内使用赋值运算符初始化对象
public class Main {
public static void main(String[] args) {
StringBuilder sb = null;
test(sb);
System.out.println(sb == null); // true
}
static void test(StringBuilder sb) {
sb = new StringBuilder("hello");
}
}
二、总结
Java中其实还是值传递的,只不过对于对象参数,值的内容是对象的引用。
值传递和引用传递的区别并不是传递的内容。而是实参到底有没有被复制一份给形参。在判断实参内容有没有受影响的时候,要看传的的是什么,如果你传递的是个地址,那么就看这个地址的变化会不会有影响,而不是看地址指向的对象的变化。
