值传递与引用传递的区别

值传递与引用传递的理解一直不深,查看了很多的博客总结了自己的理解。如有错误,可以指出改正。

在了解引用传递之前,我们首先了解一下 什么是引用,其作用到底是什么?

1 引用是什么?

在这里插入图片描述
可以说str这个变量是实例对象地址的一个别名

2 基本类型和引用类型

Java中数据类型分为基本类型的引用类型两大类

基本类型: byte、short、int、long、float、double、boolean、char
引用类型: 类、接口、数组

基本类型的变量在声明时就会分配数据空间
而引用类型在声明时只是给变量分配了引用空间,并不分配数据空间

3 值传递和引用传递

  1. 方法调用时,实际参数把它的值传递给方法的形参,形参接收的只是原始值的一个副本,后续方法里对形参的修改不会影响原来的实参的值
  2. 在方法的执行过程中,形参和实参的内容相同,指向同一块内存地址,也就是说操作的其实都是源数据,所以方法的执行将会影响到实际对象。

注意: 在JAVA中所有的传递其实都是值传递,只不过区分于理解,加了引用传递而已。(其实在引用传递的时候,是把实参的地址传递给了形参而已)

4 实际理解

4.1 值传递
public static void main(String[] args) {
    int num1 = 10;
    int num2 = 20;

    swap(num1, num2);

    System.out.println("num1 = " + num1);
    System.out.println("num2 = " + num2);
}

public static void swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;

    System.out.println("a = " + a);
    System.out.println("b = " + b);
}

运行结果:

a = 20
b = 10
num1 = 10
num2 = 20

理解:在swap方法中,a、b的值进行交换,并不会影响到num1、num2。因为,a、b中的值,只是从num1、num2的复制过来的。
也就是说,a、b相当于num1、num2的副本,副本的内容无论怎么修改,都不会影响到原件本身。

4.2 引用传递
public static void main(String[] args) {
    int[] arr = {1,2,3,4,5};

    change(arr);

    System.out.println(arr[0]);
}

//将数组的第一个元素变为0
public static void change(int[] array) {
    array[0] = 0;
}

输出结果:

0

解析:

假设arr指向的内存地址是0x11
实参arr黑色,形参array红色。
调用change()的时候,形参array接收的是arr地址值的副本,此时的array也指向了0x11。
在change方法中对0x11地址里面的值进行了修改,导致0x11地址中存储的值变为了0。
所以输出为arr[0]输出结果为0
在这里插入图片描述

在看一段代码,我们都知道String和基本类型的包装类都是不可变类。

  1. 什么是不可变类?
    就是该类被final修饰,创建了这个类的实例之后,就不容许改变他的值了。

看一下这些的源码是否被final修饰。
在这里插入图片描述
在这里插入图片描述

在看如下的代码解析过程。

public static void main(String[] args) {
    String str = "Hello";

    change(str);

    System.out.println(str);
}   
public static void change(String s) {
    s = "wolrd";
}

输出结果:

Hello

发现是不是和我们理解的,有点有出入?
在调用change方法的时候,str把他的地址副本拷贝了一份给了s。
此时的str和s都指向了一个字符串常量"hello"
那么为什么s = "wolrd"的操作 并没有影响到str呢?
在这里插入图片描述

String的API中有这么一句话:“their values cannot be changed after they are created”,
意思是:String的值在创建之后不能被更改,因为String是不可变类 被final修饰的。
API中还有一段:
String str = “abc”;
等效于:
char data[] = {‘a’, ‘b’, ‘c’};
String str = new String(data);

也就是说:对String对象str的任何修改 等同于 重新创建一个对象,并将新的地址值赋值给str。

实际上,可以转换成一种理解。

public static void main(String[] args) {
    String str = "Hello";

    change(str1);

    System.out.println(str1);
}   
public static void change(String s) {
    char data[] = {'w', 'o', 'r','l','d'};
    String str = new String(data);
    s = str;
}

然后引用指向的地址是。
在这里插入图片描述

class Person {
    String name;

    public Person(String name) {
        this.name = name;
    }
}
public class Test {
    public static void main(String[] args) {
        Person p = new Person("张三");

        change(p);

        System.out.println(p.name);
    }

    public static void change(Person p1) {
        Person person = new Person("李四");
        p1 = person; 
    }
}

输出结果:

张三

那么为什么输出结果是张三呢?看图。
在调用change方法的时候 p和p1指向通一个内存地址。
在这里插入图片描述
在change方法里面执行如下内容之后,p1的内存地址改变了。
Person person = new Person(“李四”);

在这里插入图片描述

最后的总结内容是:
值传递的时候,将实参的值,copy一份给形参。
引用传递的时候,将实参的地址值,copy一份给形参。
也就是说,不管是值传递还是引用传递,形参拿到的仅仅是实参的副本,而不是实参本身。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值