java中的参数传递(值传递和引用传递详解)

形参和实参

在学习值传递和引用传递前,我们需要了解形参/实参的概念。
方法的定义可能会用到 参数(有参的方法),参数在程序语言中分为:

  • 实参(实际参数,Arguments):用于传递给函数/方法的参数,必须有确定的值。
  • 形参(形式参数,Parameters):用于定义函数/方法,接收实参,不需要有确定的值。
String hello = "Hello!";
// hello 为实参
sayHello(hello);
// str 为形参
void sayHello(String str) {
    System.out.println(str);
}

值传递和引用传递

程序设计语言将实参传递给方法(或函数)的方式分为两种:

  • 值传递:方法接收的是实参值的拷贝,会创建副本。
  • 引用传递:方法接收的直接是实参所引用的对象在堆中的地址,不会创建副本,对形参的修改将影响到实参。

很多程序设计语言(比如 C++、 Pascal )提供了两种参数传递的方式,不过,在Java中只有值传递,基本数据类型传递的是值的副本,引用数据类型传递的是引用的副本。

1.值传递

1)传递基本数据类型

public class Demo03 {
    public static void main(String[] args) {
        int a = 1;
        System.out.println(a);//a=1
        Demo03.change(a);
        System.out.println(a);//a=1
    }
    public static void change(int num1){
        num1=10;
    }
}

change方法中,对num1的值进行修改,并不会影响到 a。因为num1的值只是从 a的复制过来的。也就是说,num1相当于 a的副本,副本的内容无论怎么修改,都不会影响到原件本身。
通过上面例子,我们已经知道了一个方法不能修改一个基本数据类型的参数,而对象引用作为参数就不一样

2)传递引用数据类型

public class Demo02 {
    public static void main(String[] args) {
        Perosn perosn = new Perosn();
        System.out.println(perosn.name); //nuLL
        Demo02.change(perosn);
        System.out.println(perosn.name); //NNN
    }
    public static void change(Perosn perosn1){
        //perosn是一个对象:指向的---> Perosn perosn = new Perosn();
        //这是一个具体的人, 可以改变属性!
        perosn1.name = "NNN";
    }
}
//定义了一个Perosn类,有一个属性: name
class Perosn{
    String name; //默认值null
}

看了这个案例很多人肯定觉得 Java 对引用类型的参数采用的是引用传递。
实际不然,这里传递的还是值,只是这个值是实参的地址。也就是说 change 方法的参数拷贝的是 perosn (实参)的地址,因此,它和 person 指向的是同一个对象。这也就说明了为什么方法内部对形参的修改会影响到实参。
为了证明Java对引用数据类型采用的不是引用传递,我们再来看下面这个案例!

public class Person {
    private String name;
   // 省略构造函数、Getter&Setter方法
}

public static void main(String[] args) {
    Person xiaoZhang = new Person("小张");
    Person xiaoLi = new Person("小李");
    swap(xiaoZhang, xiaoLi);
    System.out.println("xiaoZhang:" + xiaoZhang.getName());
    System.out.println("xiaoLi:" + xiaoLi.getName());
}

public static void swap(Person person1, Person person2) {
    Person temp = person1;
    person1 = person2;
    person2 = temp;
    System.out.println("person1:" + person1.getName());
    System.out.println("person2:" + person2.getName());
}

//输出
person1:小李
person2:小张
xiaoZhang:小张
xiaoLi:小李

两个引用类型的形参互换并没有影响实参!swap方法的参数person1person2只是拷贝的实参xiaoZhangxiaoLi的地址。因此,person1person2的互换只是拷贝的两个地址的互换罢了,并不会影响到实参xiaoZhangxiaoLi

2.引用传递

C++ 的代码为例,看一下引用传递的庐山真面目。

#include <iostream>

void incr(int& num)
{
    std::cout << "incr before: " << num << "\n";
    num++;
    std::cout << "incr after: " << num << "\n";
}

int main()
{
    int age = 10;
    std::cout << "invoke before: " << age << "\n";
    incr(age);
    std::cout << "invoke after: " << age << "\n";
}

//输出
invoke before: 10
incr before: 10
incr after: 11
invoke after: 11

可以看到,在incr函数中对形参的修改,可以影响到实参的值。要注意:这里的incr形参的数据类型用的是int&才为引用传递,如果是用int 的话还是值传递哦!

3.Java的String类型

public class Test {
    public static void main(String[] args) {
        String a = "A";
        append(a);
        System.out.println(a);//A
    }
    static void append(String str){
        str+="is a";
    }
}

String毫无疑问不是基本数据类型,因此传递的是引用对象的内存地址。但为什么值没有被修改呢?
答:通过查看源码可知,String类是使用char类型的value数组来存储字符串的,final修饰,所以String类的值(实例对象)不可修改,即final修饰符导致了String一旦定义就是最终形态,任何试图改变String值的操作都只能重新开辟地址。因此当我们使用代码str="xxxx"的时候,会返回一个新的String对象。
请添加图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值