一、引言
1、描述
对于C++来说,调用方法时存在值传递(新产生的副本不影响原来的)和引用传递(会影响原来的值),那么对于Java呢?
2、Java传递介绍
通过查阅资料,java中不存在引用传递,始终是值传递。Java里面传的任何参数都是传的“值的副本”,如果是对象那么传递的是指针的“值的副本”,所以会有以下几种情况:
- 8种基本类型,传的是值的副本,在另外的方法里面修改值,当前函数的值都不会改变;
- 对于final修饰的包装类对象,且没有提供方法对自身进行修改的对象,比如String、Integer…对变量进行赋值操作实际上是把传进来的引用的副本改变成了一个新的对象的引用,不会影响到原来的引用里面的对象;
- 提供方法对自身进行修改的对象,如StringBuffer…对象自身对自身进行改变,引用没有被改变,所以原方法里面的引用也会跟着改变;
- 数组名(相当于把数组的头指针的“值的副本”传递进来),而arr[i]可以理解为是根据地址计算实际的数据位置偏移来操作数组当中的某个元素,所以原方法当中也会跟着改变,如果是直接给arr赋一个新值就相当于重新创建一个新对象了。
二、实战验证
1、8种基本类型
public class Method {
public static void main(String[] args) {
int a = 1;
char c = 'a';
change(a, c);
// 输出仍是 1、a
System.out.println(a);
System.out.println(c);
}
static void change(int a1, char c1) {
a1 = 2;
c1 = 'c';
}
}
2、final修饰的包装类对象
对于String、Integer等对象会生成新的对象,因此传递到方法时并不会修改原来的值,因为final修饰符表示对象不可变。
main方法栈中的引用地址name、c传递给方法,因为String等对象不可修改,所以java会重新创建一个对象,此时新生成的对象指向局部变量,因此对原先变量不产生影响
public class Method {
public static void main(String[] args) {
Integer a = 1;
String c = "lemon";
String name = new String("shawn");
change(a, c,name);
// 输出仍是 1、lemon、shawn
System.out.println(a);
System.out.println(c);
System.out.println(name);
}
static void change(Integer a1, String c1,String name1) {
a1 = 222;
c1 = "lemon22";
name1 = new String("shawn22");
}
}
3、提供方法对自身进行修改的对象
这里举例StringBuilder对象和自定义类对象,传值传过来的是对象地址,对象本身内容可修改,且提供了方法对自身内容进行修改
public class Method {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("hello ");
Test test = new Test();
test.setName("shawn");
test.setPassword("123456");
change(test,stringBuilder);
// hello world!
// Test(name=lemon, password=123456)
System.out.println(stringBuilder);
System.out.println(test);
}
static void change(Test test1,StringBuilder stringBuilder1) {
test1.setName("lemon");
stringBuilder1.append("world!");
}
}
@Data
class Test {
private String name;
private String password;
}