Java中的值传递和引用传递

  最近在写程序的时候遇到了一个问题,先来看下面一个小例子:

public class Case1 {
    
    public static void increment(int x) {
        x++;
    }

    public static void AppendString1(String s) {
        s += "Java";
        return;
    }
    
    public static void main(String[] args) {
        String test = new String("Hello");
        System.out.println("原先的字符串是 : " + test);
        AppendString1(test);
        System.out.println("给字符串添加后缀后: " + test);
        int x = 5;
        System.out.println("x原来的值:" + x);
        increment(x);
        System.out.println("x加1后:" + x);
    }

}

  以下是程序的输出结果:

原先的字符串是 : Hello
给字符串添加后缀后: Hello
x原来的值:5
x加1后:5

  然,执行increment方法后x的值并不会改变,但是AppendString1方法也没有成功给“Hello”加上后缀,这是怎么回事呢?

  首先来看看Java中的两种变量类型,基本变量类型和引用变量类型。每个变量实际上都代表一个存储值的内存位置,声明一个变量时,就是在告诉编译器这个变量存放什么类型的变量。对于基本类型来说,对应内存所存储的就是这个基本类型的一个值;对于引用类型来说,对于内存所存储的值是一个引用地址,这个引用地址是实际对象的存储地址,即引用指向实际对象,实际对象中保存内容。变量在内存中的存储内容如下图所示:

  理解了这两种不同的变量类型,接下来是“=”操作。=是赋值操作,其他+=、-=、*= 和 /= 等操作符其实都包含了赋值操作这一步。而这个赋值操作实际上又包括两步:1.放弃原来的值或者引用;2.获得=号右边的值或引用。下面这条语句: ClassName objRef = new ClassName() , 实际上包含了声明一个对象引用型变量objRef、创建一个ClassName类的对象、将这个对象的引用赋给变量objRef三个步骤。

  在方法调用的过程中,参数传递实际上就是一次赋值操作。在调用带参数的方法时,实参的值要传给形参,这个过程称为值传递(pass-by-value)。方法的形参实际上也是一个变量,如果形参是基本型变量,那么传递的是基本类型的值的一个拷贝;如果形参是引用型变量,那么传递的就是实参这个变量所引用的对象在堆中的地址值的拷贝。无论形参在方法中是否改变,提供传递值的实参变量都不受影响。因为形参在方法中是作为局部变量存在的,当方法调用结束返回到上层调用者的时候,如果不是作为返回值被返回,它就消失了。在上面的例子中,main方法中的test字符串和传入AppendString1方法的参数s字符串一开始都指向堆中的同一个字符串对象,如下左图所示,调用AppendString1方法后,由于String对象的不可变性(immutability),“+=”操作生成一个新的字符串对象,并把这个新的字符串对象的引用赋给s,而test变量存储的引用地址值仍没变,如下右图所示:

  在上面的程序中,如果要改变test变量所引用的字符串对象的值,就要进行赋值操作,让方法返回一个String类型的新的引用型变量并且赋值给test。

  此外,还有另外一个小例子,代码如下所示:

public class A {
    String ID;
    int cnt;

    public A() {
        ID = new String("I am A.");
        cnt = 0;
    }
}

public static void setID (A a) {
    a.ID = new String("I was modified.");;
}
    
public static void main(String[] args) {
    A case = new A();
    System.out.println(case.ID);
    setID(case);
    System.out.println(case.ID);
}

  结果如下:

I am A.
I was modified.

  在这个例子中,setID方法的参数a拷贝了引用型变量case指向的的A类对象的地址值,这时候a和case都指向同一个对象,并且在整个setID方法中,a的值都没有发生变化,因此这个方法的操作改变了这个对象中的内容,虽然方法调用结束后变量a消失了,但是case指向的对象的内容确实发生了变化,即ID被改变了,但是case存储的地址值仍然是不变的(因为程序中没有任何对它进行赋新值的操作)。

  总结一下,Java调用方法时参数的传递实际上就是一个赋值操作,因此也有人说Java没有引用传递,不要和C++中的传引用传指针混淆了。

转载于:https://www.cnblogs.com/njufl/p/6506257.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值