Java中值传递与引用传递

来源:互联网 发布:怎么安装mysql 编辑:程序博客网 时间:2024/05/20 08:02

呵呵,其实地球人都知道Java中只有值传递,没有引用传递(啥?你不知道?那你面试咋过的。。。),但是有没有深究一下这是为什么呢?


引用这玩意儿应该是Java中的概念,对应C和C++里面的指针。Java中的数据类型分为基本类型和引用类型,基本类型指的就是常见的byte、short、int、long、float、double、char、boolean八种基本类型,这八种类型的变量,存储的就是值本身,比如short a = 5; 那么内存中会分配一块空间,它的名字是a(这里只是为了理解的方便,内存空间块并没有名字。。),里面存放的数据就是二进制的5,其他几种类似。

除了基本类型,就是引用类型了。比如我们常见的String类型,就是引用类型。String c = "ffef"; 那么给变量c分配的内存空间里存放的就是"ffef"吗?No,too young too simple!  变量c中存放其实是一个地址值,这个地址值指向的是Java堆上一块空间。要想获取c真正的内容,首先获取里面存放的地址值,然后再访问这个地址代表的内存,才能得到"ffef"。


好了,以上只是前提,下面开始说值传递。所谓值传递,指的是调用java方法时,方法得到的只是参数的一个副本,并不是参数本身。看代码:

int b = 5;int c = plus(b);int plus(x) {     x = x + 1;     return x;}
那么调用plus之后,b的值会变吗?不会,因为调用plus时,实际上是方法的栈变量x复制了b的值,plus并不直接操作b,这就是所谓的值传递。


那么怎么才算是引用传递呢?那就看个C或C++里面的例子:

int plus(int* x) {    *x = *x + 1;    return *x;}int b = 4;int c = plus(&b);
这段代码执行完毕之后,b和c的值都会是5,因为传递给plus的是b的地址,也就是plus函数会直接操作b代表的内存空间本身。


现在再来看,如果Java中的方法的参数是一个引用类型,也就是Java中的“指针”,会发生上面的情况吗?

public class Apple {private int weight;public static Apple changeWeight(Apple x) {x.weight += 10;return x;}public int getWeight() {return weight;}public void setWeight(int weight) {this.weight = weight;}public static void main(String[] args) {Apple a = new Apple();a.setWeight(20);Apple b = changeWeight(a);System.out.println(a.getWeight());System.out.println(b.getWeight());}
打印结果是,二者都是30。表面上看,将a传递给方法之后,a被改变了,这就像在上面C语言的代码中指针传递的效果一样。然而,实际上呢?
上面说过,存储在变量a中的值实际上是一个“地址”,这个地址指向了堆中的一块内存空间;将a传递给changeWeight方法之后,该方法栈变量x复制了a的值,即x中的地址值也指向堆中的同一块空间。所以该方法确实是在操作a所真正指向的对象,这个对象的值改变之后,a作为对象的引用自然跟着改变。

矛盾吗?No,问题的核心在于,a的值变了吗?No,a还是指向原来的对象,changeWeight方法操作的是对象而不是变量a本身!引用类型的变量说穿了只是对象的一个影子而已,如果方法能够直接改变本体,那么影子自然也会改变——但是影子仍然对应着原来的本体。


Java只有对象的“指针”,并把它存储到引用类型的变量中,但是没有变量的“指针”。在调用Java方法时,传递给它的只是变量的副本(数值),不是变量本身(即地址或指针,Java没有机制传递这玩意儿),故Java(在方法调用时)只有值传递,没有所谓的引用传递。

0 0