Java中的参数传递问题

在程序设计语言中,参数传递方法一般有两种
按值调用(call by value):方法接收的是调用者提供的值。
按引用调用(call by value):方法接收的是调用者提供的地址。

很多人认为,在Java中也存在两种参数传递的方法:
对于基本数据类型,Java中采用的是值传递;对于对象,Java中采用的是引用传递。


先看一段代码:

int a = 0;
int b = 1;
swap(a, b);
System.out.println("In Main: a=" + a + "; b=" + b);

public void swap(int a, int b) {
    a = a + b;
    b = a - b;
    a = a - b;
    System.out.println("In Swap: a=" + a + "; b=" + b);
}

运行结果如下:

In Swap: a=1; b=0
In Main: a=0; b=1

很显然,在swap方法中的参数是两个基本数据类型,最终的运行结果也验证了我们的猜想,对于基本数据类型,Java中进行的是值传递。但是对象在Java中是传递的引用吗?

//定义一个类Dog
class Dog {
    String name = "";

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

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

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return name;
    }
}
//方法changeDogName
public void changeDogName(Dog dog, String name) {
    dog.setName(name);
}

//创建一个名为"Peter"的Dog对象,然后修改它的名字。
Dog A = new Dog("Peter");
changeDogName(A, "Sam");
System.out.println("In Main: A=" + A + ";");

运行结果为:
In Main: A=Sam;
按结果来看,对于方法changeDogName,参数貌似就是按照引用调用的。

再看一个方法:

Dog A = new Dog("Peter");
Dog B = new Dog("Kaka");
swap(A,B);
System.out.println("In Main: A=" + A + "; B=" + B);

public static void swap(Dog x, Dog y) {
    Dog temp = x;
    x = y;
    y = temp;
}

如果按照Java中对象作为参数时是传递的引用,那么最终的结果,A和B一定会进行交换。但是运行之后发现:
In Main: A=Peter; B=Kaka

A和B的并没有按照我们所想象的那种交换,这种结果倒是很符合按值调用。

其实,在swap(Dog x, Dog y)中,参数x和y被初始化为main方法中两个对象A和B引用的拷贝,也就是地址的拷贝。而在方法swap()中,实际交换的是这两个拷贝。

  1. 最初,A指向堆内存中Dog(“Peter”)对象,A的值就是Dog(“Peter”)在堆内存中的地址,同理B指向堆内存中Dog(“Kaka”)对 象;
  2. 在调用方法swap(x,y)之后,x和y分别指向堆内存中的Dog(“Peter”)和Dog(“Kaka”),x和y分别是A和B地址值的两个副本(拷贝),x和y存在于栈内存中(对象存在于堆内存);
  3. 在方法swap执行时,x和y的地址值进行了交换,y指向Dog(“Kaka”),x指向Dog(“Peter”),但是对于A和B来说,这并没有任何的影响,A和B的地址值并没有任何改变,因此仅仅交换A和B的副本不会导致A和B自身发生改变,方法执行完成后,x和y就被会释放掉。

而在方法changeDogName(Dog dog, String name)中,参数dog同样是A的副本,它们都指向堆内存中Dog(“Peter”),对dog调用方法setName(String name),实际改变的是堆内存中Dog(”Peter”)的name属性,并不会改变A的地址值,A并没有被改变,只不过是A所指向的对象属性发生了改变。


在Java核心技术上解释道:Java程序设计语言对对象采用的不是引用调用,实际上,对象引用进行的是值传递。

其实最好的理解方法就是,不论是基本数据类型还是对象,传递的都是参数的副本。对于基本数据类型,副本就是原始参数的值;对于对象,副本就是参数的地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值