一直想写一个关于Java的读书系列帮助自己梳理知识总是无从开始,最近把Think In Java 又重新看了一遍决定写个读书笔记
关于Java的值传递与引用传递
一直以来关于Java是值传递还是引用传递都是争论不断,一种观点认为Java中只有值传递,另一种观点认为Java有值传递和引用传递两种,其实只是说法不同。
说只有值传递是将参数为应用的情况时传递的应用当成一种特殊值,而说值传递和引用传递都有的观点显然是将这两种情况分开看待了,这里我们暂且不去讨论它的叫法直说原理。
当传递的参数为基本数据类型时
public class JavaTest {
public int test1(int a) {
a= a+6;
return a;
}
public void test2(int a) {
a= a+6;
}
public static void main(String[] args) {
int a = 10;
JavaTest javaTest = new JavaTest();
System.out.println(javaTest.test1(a));
javaTest.test2(a);
System.out.println(a);
}
}
方法一
代码中的基本数据类型传参test1方法中传入参数a此时形参实际上是实参a的一个数据拷贝传入的是a一个副本当在方法中完成对a的操作后test1返回了a此时返回的a是方法test1中的形参a实际上主方法中的a并没有发生变化返回的实际是方法test1的局部变量a因为在方法中对形参a进行了修改所返回为修改后的数据16。
方法二
在方法test2中方法test1的操作相同但没有返回值也就是没有将方法中的局部变量返回方法对局部变量的操作不会对实参造成影响所以输出为10.
综合上述两种方法可知当参数为基本数据类型时方法得到一个实参的副本进行操作对实际参数没有影响。
方法参数为引用数据类型
public void test3(Student student) {
student.setAge(100);
}
public Student test4(Student student) {
student.setAge(200);
return student;
}
/***引用数据类型****/
Student student = new Student(10, "zs");
javaTest.test3(student);
System.out.println(javaTest.test4(student));
System.out.println(student.toString());
方法三和方法四
在方法test3和test4中对引用数据类型Student进行了相同的操作,在参数为引用数据类型时传入的参数依旧是一个实参的一个拷贝副本只是这里是一个引用拷贝是当前对象的地址拷贝,这里就可以解释为什么有观点认为Java中只有值传递以这个角度来说地址也是一个特殊的值,可以认为是值传递。
对引用的操作实际会作用到这个引用所指向的对象上,所以对于方法test3和test4不论是否有返回值Student对象的值都已经被修改所以输出结果相同都是Studuent修改后的结果。
入参为String类型时
public String test5(String string) {
string = string+"Java";
return string;
}
public void test6(String string) {
string = string+"Java";
}
String string = "Hello World!";
javaTest.test5(string);
javaTest.test6(string);
System.out.println(javaTest.test5(string));
System.out.println(string);
String是一种特殊的参数类型String类被Final修饰,当传参为String类型时和引用数据类型一样传递的是当前对象的引用拷贝
如图:
由于String为final类型对于String的操作会产生新的对象方法test5中引用拷贝被新的对象地址所覆盖指向了新的地址,在test6中对String的修改没有作用到原来的String上(String是final的无法修改,修改产生新的对象但没有返回所有实参没有改变)