java中的值引用_Java中的值传递和引用传递

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

public classCase1 {public static void increment(intx) {

x++;

}public static voidAppendString1(String s) {

s+= "Java";return;

}public static voidmain(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原来的值:5x加1后:5

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

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

0d3e8bb321682f5ae4c6a51c2cf50497.png

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

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

6c1332f366801d5792b075000d86b56c.png

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

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

public classA {

String ID;intcnt;publicA() {

ID= new String("I am A.");

cnt= 0;

}

}public static voidsetID (A a) {

a.ID= new String("I was modified.");;

}public static voidmain(String[] args) {

A case= newA();

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++中的传引用传指针混淆了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值