为什么Java中只有值传递【详解】

目录

一、为什么Java中只有值传递

1、有此疑惑的原因

2、首先搞清楚:什么是形参和实参

3、其次弄明白:什么是值传递和引用传递

4、3个Java中值传递的例子

基本数据类型:

引用数据类型:对象

引用数据类型:字符串

5、总结

6、补充:深拷贝与浅拷贝


一、为什么Java中只有值传递

1、有此疑惑的原因

出现这个疑惑的最大原因是未能真正理解值传递和引用传递的含义

 

2、首先搞清楚:什么是形参和实参

形参:指的是函数定义时使用的参数;

实参:指的是调用函数时,传递给函数的参数;

package com.zibo.java.february.first;

// 说明什么是形参和实参
public class MyParameter {
    public static void main(String[] args) {
        int num = 10;
        doSth(num); // 这里的num是实参
    }

    private static void doSth(int num) {
        num = 100; // 这里的num是形参
    }

}

 

3、其次弄明白:什么是值传递和引用传递

值传递:指的是在调用函数时,将实参拷贝一份赋值给函数的形参,对形参进行操作

引用传递:指的是在函数调用时,将实参传递给函数,直接对实参进行操作

天大的误解:传递的是基本数据类型就是值传递,传递的是引用数据类型就是引用传递!

伪代码解释:

package com.zibo.java.february.first;

// 演示值传递和引用传递的逻辑
public class MyValue {
    public static void main(String[] args) {
        // 值传递:指的是在调用函数时,将实参拷贝一份赋值给函数的形参,对形参进行操作;
        // java只有值传递,java就是这么个逻辑,实参和形参是相互独立的;
        // 你传进来谁,我就将谁复制一份进行操作,不对原变量进行改变
        // 基本数据类型
        int x = 1; // 原始变量,原本的实参
        // 此处省略函数调用
        int y = x; // 新变量,形参,此时y的值就是1
        y = 100; // 形参怎么改变,实参不会收到任何影响

        // 引用数据类型
        Student a = new Student(); // 原始变量,原本的实参,a的值是new Student()对象的引用地址
        // 此处省略函数调用
        Student b = a; // 新变量,形参,此时b的值并不是前面的new Student()的实际对象,而是引用地址
        // 因为变量a本来存储的就是引用地址,赋值给a,所赋值的肯定也是引用地址,a和b指向同一个对象;
        b.setName("小明"); // 此时,a和b同时指向的new Student()对象的name会发生改变
        b = new Student(); // 此时a和b指向的就不是一个对象了,对b进行任何操作,a所指向的对象都不会改变

        // 引用传递:指的是在函数调用时,将实参传递给函数,直接对实参进行操作;
        // 在引用传递中大致逻辑是这样的,没有实参和形参的区分,你传进来谁,我就对谁进行操作
        int x = 1; // 原始变量
        // 此处省略函数调用
        int y = x; // 这个y就完全等于x,对y的任何操作,就等于对x的任何操作;
        // 对于引用数据类型,也是一样的,你传过来的变量就是函数所操作的变量;

        /*
         * 区别:
         * 1、值传递:锁定变量的值,对变量的值进行操作,无论是基本数据类型的数值,还是引用数据类型的引用地址;
         * 2、引用传递:锁定变量本身,对变量进行直接操作,相当于顺序执行的代码;
         */
    }
}

 

4、3个Java中值传递的例子

基本数据类型:

代码:

package com.zibo.java.february.first;

public class MyBaseData {
    public static void main(String[] args) {
        int x = 10; // x是实参,x的值是10
        System.out.println("函数执行之前x的值:" + x);
        change(x);
        System.out.println("函数执行之后x的值:" + x);
    }

    private static void change(int a) {
        System.out.println("函数接收到的形参a的值:" + a);
        a = 100;
        System.out.println("形参被更改之后的a的值:" + a);
    }
}

执行结果:

函数执行之前x的值:10
函数接收到的形参a的值:10
形参被更改之后的a的值:100
函数执行之后x的值:10

说明 :

这里,我们可以清晰地看出x的值在函数执行前后没有发生改变,函数对形参的任何操作,不影响实参;

解析:

 

引用数据类型:对象

代码:

package com.zibo.java.february.first;

public class MyObj {
    public static void main(String[] args) {
        Student student = new Student("訾博");
        System.out.println("函数执行前的student:");
        System.out.println(student);
        change(student);
        System.out.println("函数执行后的student:");
        System.out.println(student);
    }

    private static void change(Student s) {
        s.setName("大哥");
    }
}
class Student{
    private String name;

    public Student() {
    }

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}

执行结果:

函数执行前的student:
Student{name='訾博'}
函数执行后的student:
Student{name='大哥'}

说明:

有人问了,这就有意思了呀!你不是说值传递不改变实参吗,这不是改变了?!

这是最容易产生误解的地方了,值传递确实没有改变原始变量student,但是原始变量student存储的是new Student("訾博")对象的引用地址,当调用change()函数的时候相当于将引用地址赋值给了形参,也就意味着两个变量同时指向一个对象,change()函数对new Student("訾博")对象的改变同样会显现在实参变量上,见图解;

图解:

在不重写toString()函数的情况下输出变量student的值,我们可以看到两个相同的值:

函数执行前的student:
com.zibo.java.february.first.Student@4554617c
函数执行后的student:
com.zibo.java.february.first.Student@4554617c

 

引用数据类型:字符串

代码:

package com.zibo.java.february.first;

public class MyStr {
    public static void main(String[] args) {
        String name = "訾博";
        System.out.println("函数执行前的name:");
        System.out.println(name);
        change(name);
        System.out.println("函数执行后的name:");
        System.out.println(name);
    }

    private static void change(String n) {
        n = "大哥";
    }
}

执行结果:

函数执行前的name:
訾博
函数执行后的name:
訾博

说明:

这咋没变?因为Java中字符串是一个常量,每次修改字符串并不是修改了原来的值,而是创建一个新的字符串并将原来的变量指向新的字符串引用;

图解:

 

5、总结

Java方法传参,都是对所传变量进行拷贝,对基本数据类型来讲,拷贝的是实际数值,对引用数据类型来讲拷贝的是引用地址;

Java中不存在函数对实参的操作,全部是对经过拷贝的形参的操作,也就是说Java中只存在值传递,不存在引用传递。

 

6、补充:深拷贝与浅拷贝

深拷贝指的是拷贝对象本身,浅拷贝指的是拷贝对象的引用地址,java的方法传参是一种浅拷贝。

 

 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值