Java只有值传递
可能有很多小伙伴都知道Java是值传递,但是又说不出个所以然,我也是这样,于是去看了一些博客,下面来一个简单的总结。
首先说结论:Java中只有值传递,没有引用传递。
这里涉及到值传递和引用传递两种传递机制:
值传递(pass by value):是指在调用方法(或者函数)时,将实际参数复制一份传递到方法(或者函数)中,这样在函数中如果对形式参数进行修改,将不会影响到实参。
引用传递(pass by reference):在调用方法(函数)时,将实参的地址直接传递到函数中,那么在函数中对形参进行修改,将影响到实参。
下面来看看上面定义的重点:
值传递 | 引用传递 | |
根本区别 | 复制实参 | 不复制实参 |
修改的是什么? | 形参 | |
实参改变否? | 不改变 | 改变 |
实参和形参的概念我想不必再提了,大家应该都懂。
可能看到这里有的小伙伴会说:基本数据类型是值传递,引用数据类型是引用传递。
以前我也是这么认为,但是实际上是错误的。我们再看看我们修改的是什么?
形参啊!你传递了一个对象进去,结果修改的是对象的属性,对象的属性是你传的形参吗?即使你把对象的所有属性都改了,那也不是形参啊!!!!
为了方便理解,我们先看下图:
基本数据类型在栈中保存的就是变量,但是引用数据类型在栈中保存的是地址,凭什么你传给形参的时候传栈里面的值,但是你修改的时候要修改堆里面的内容?
所以我们应该修改的形参也应该是栈中的数据。
下面我们直接来看代码验证我的结论:
public class Demo04 {
public static void main(String[] args) {
int a = 2;
System.out.println(a);//结果为2
//值传递
change(a);
System.out.println(a);//结果为2
}
public static void change(int a){
a = 10;
}
}
对于这里的结果大家应该没有异议。接下来看这段代码:
public class Demo05 {
public static void main(String[] args) {
String str = "学渣很忙";//String可是引用数据类型哟
System.out.println(str);//学渣很忙
change(str);
System.out.println(str);//学渣很忙
}
public static void change(String str){
str = "张三";
//上面这句话等价于下面这句话,忽略入不入字符串常量池
//str = new String("张三");
}
}
为什么对于引用数据类型String来说,前后的结果并没有改变呢?看了change方法的注释你大概就懂了,修改形参的值就是new
了一块新的内存空间,也就是说我们修改的是将栈中原来保存的地址值复制了一份给形参,然后形参中修改了这个地址值。内存图如下
需要明确的一点是,我们在被调方法(函数)中操作的是形参,而复制的一份形参也是压入栈中,所以修改形参应该是修改栈中的值。
然后就是修改形参的值,对于基本数据类型就可以直接在栈中修改;对于引用数据类型需要通过保存在栈中的地址值找到堆中的数据。但是这并不影响我们修改形参,如果此时你修改的不是形参而是堆中的属性,那当然会对属性产生影响。但是我们要修改形参,也就是new 一个新的内存空间,把new出来的地址值赋值给形参,这才是真正的修改形参。
最后是结果比较,如果你真的是修改的形参,你在内存图中看看原来的实参有没有变化呢?答案是实参没有改变。
我的结论得到了验证:Java中只有值传递,没有引用传递。小伙伴们可以试一下对0x1234进行修改,然后画画内存图作为练习;下面是我给出的答案:
public class Demo06 {
public static void main(String[] args) {
Student student = new Student();
student.name = "张三";
student.age = 21;
System.out.println("修改形参前的student:"+student);
change(student);
System.out.println("修改形参后的student:"+student);
changeAttribute(student);
System.out.println("修改属性后的student:"+student);
}
//这里才是修改的形参
public static void change(Student student){
student = new Student();
student.name = "王麻子";
student.age = 35;
System.out.println("change方法中的student:"+student);
}
//这样修改是修改的属性,而不是参数
public static void changeAttribute(Student student){
student.name = "李四";
student.age = 12;
}
}
class Student{
String name;
int age;
@Override
public String toString() {//用来输出对象的名字和年龄的
return "name=" + name + ", age=" + age;
}
}
这是运行结果:
内容到这儿就结束啦,初学小白,如有错误烦请各位大佬及时指出!感谢!