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;
    }
}

这是运行结果:

 

 内容到这儿就结束啦,初学小白,如有错误烦请各位大佬及时指出!感谢!

原文地址:https://www.cnblogs.com/xzhm/p/12965334.html