您可以在这里快速查找:


 
您的位置: 编程学习 > java教程 > 200505
文章分类

Java技术
2005: 03 04 05 06 07 08
09 10 11 12
2006: 01 02

Asp.net
2005: 07 08 09 10 11 12
2006: 01 02

VB编程
2006: 02

Asp编程
2005: 11 12
2006: 01 02

C++/VC
2005: 10 11 12
2006: 01 02

Delphi
2005: 12
2006: 01 02

其它

 本文章适合所有读者

Java “Pass by value” 解析

sxhv998

Java  “Pass by value” 解析

我在许多论坛和文章的答复上看到很多人都认为Java是pass by reference的,但我查了些资料,确实Java是pass by value的。如果你已了解java是pass by vlaue而非pass by reference的,那么你就可以pass这篇文章了,看其他你喜欢的文章去吧!如果你不以为Java是pass by vlaue或还坚信Java是pass by reference的,那么就跟着我的思路走一下吧。我会让你了解Java到底是pass by value还是pass by referenve。本人是个菜鸟,只是把自己所学的东西写出来给同级别的菜鸟学习学习。望高手看了多多指教,不要见笑。

 

Java是使用“pass by value”『函数调用』方式,这常常造成许多人迷惑。在所有地点,Java都严格采用pass by value。让我们来看一个简单的例子:

 

清单一:

class Param {

    public static void main (String[] args) {

        int x = 5;

        triple(x);

        System.out.println ("x after triple: " + x);

    }

    private static void triple (int arg) {

        arg = arg * 3;

        System.out.println ("arg in triple: " + arg);

    }

}

 

会产生这样的输出:

arg in triple: 15

x after triple: 5

 

这段代码只是传入一个int而已,还不至于让人糊涂。但如果参数中传递的是一个对象,就可能把你弄迷糊了。如果我在程序中以Date对象表示日期,那么程序看起来想这样:

 

清单二:

import java.util.*;

 

class Param {

    public static void main (String[] args) {

        Date d1 = new Date ("1 Jan 2004");

        nextDateUpdate (d1);

        System.out.println ("d1 after nextDay: " + d1);

   

        Date d2 = new Date ("1 Jan 2004");

        nextDateReplace (d2);

        System.out.println ("d2 agter nextDay: " + d2);

    }

    private static void nextDateUpdate (Date arg) {

        arg.setDate (arg.getDate() + 1);

        System.out.println ("arg in nextDay: " + arg);

    }

    private static void nextDateReplace (Date arg) {

        arg = new Date (arg.getYear(),arg.getMonth(),arg.getDate() + 1);

        System.out.println ("arg int nextDay: " + arg);

    }

}

 

会产生这样的输出:

arg in nextDay: Jan 02 00:00:00 CST 2004

d1 after nextDay: Jan 02 00:00:00 CST 2004

arg int nextDay: Jan 02 00:00:00 CST 2004

d2 agter nextDay: Jan 01 00:00:00 CST 2004

 

这个实例可能让你看起来有点迷惑。有人会说如果java是pass by value的话,d1 after nextDay:应该为Jan 01 00:00:00 CST 2004才对!错!Java中的对象是object reference。事实上,nextDateReplace()是在与『Date对象(d2)的reference的复件』打交道,而不是与『Date对象(d2)的复件』打交道。在进入nextDateUpdate(Date arg)之时,这个对象看起来象这样:

 

聪明的你这下应该明白了吧!如果还没明白!没关系,再来一个更详细的例子:

 

 

清单三:

import java.awt.Point;

 

class Param {

    public static void main (String[] args) {

        Point p = new Point(0,0);                    //1

        int i = 10;

        System.out.println ("Before modifyPoint: " + "p = " + p +

                            " and i = " + i);

        modifyPoint (p,i);                            //2

        System.out.println ("After modifyPoint: " + "p = " + p +

                            " and i = " + i);

    }

      

    private static void modifyPoint (Point pt , int j) {

        pt.setLocation (5,5);                        //3

        j = 15;

        System.out.println ("During modifyPoint: " + "pt = " + pt +

                            " and j = " + j);

    }

}

 

会产生这样的输出:

Before modifyPoint: p = java.awt.Point[x=0,y=0] and i = 10

During modifyPoint: pt = java.awt.Point[x=5,y=5] and j = 15

After modifyPoint: p = java.awt.Point[x=5,y=5] and i = 10

 

这段代码在//1处建立了一个Point对象并设初值为(0,0),接着将其值赋予Object reference变量p。然后对基本型别int I赋予数值10。//2调用static   modifyPoint(),传入p和i。modifyPoint()对第一个参数pt调用了setLocation(),将其坐标改为(5,5)。然后将第二个参数j赋值为15。当modifyPoint()返回的时候,main()打印出p和i的值。

根据程序输出,modifyPoint()改变了//1所建立的Point对象,却没有改变int i。在main()之中,i被赋值为10。由于参数通过by value方式传递,所以modifyPoint()收到i的一个副本,然后它将这个副本改为15并返回。main()内的原值i并没有受到影响。

对比之下,你或许认为//1建立的point对象也没有被modifyPoint()修改。毕竟Java是pass by value方式来传递参数。于是乎,当调用modifyPoint()并传入//1所建立的point对象时,就会产生一个复件配合modifyPoint()工作。modifyPoint()之中对于point对象所做的修改不会反映到main()中,因为它们是两个不同的对象嘛。对不对?错!

事实上modifyPoint()是在与是在与『point对象的reference的复件』打交道,而不是与『point对象的复件』打交道。你知道的,p是个object reference,并且Java是pass by vlaue方式传递参数。更明确的说,Java是以by value方式传递object reference当p从main()被传入modifyPoint()时传递的是p(也就是一个reference)的复件。所以modifyPoint()是在与同一个对象打交道,只不过通过别名pt罢了。在进入modifyPoint()之后和执行//3之前,这个对象看起来象这样:

所以//3执行过后,这个point对象已经改变为(5,5)。

    结语:通过上面说的,Java是pass by value方式传递参数的。当然就算你已知道java是pass by value方式传递参数的,它有时也会让你感到迷糊。从本质上说,object reference是按值传递的(pass by value),因此我们能够修改参数对象的内部状态。我们应该采用《重构》中的‘Remove Assignments to Parameters’进行重构,以此来避免可能发生的问题。