• 2004-11-08

    当Java遭遇OUT参数

    Tag:向上走

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/dreamhead-logs/485504.html

    用Java写一个交换两个数的程序,这还不简单,下面是很容易写出的一个:
        void swap(int a, int b) {
            int temp = a;
            a = b;
            b = temp;
        }
    熟悉Java的你轻而易举的就看出了问题所在,在Java语言中,基本类型作为参数是通过传值(pass by value)的方式进行传递的,所以,这里改变的是传过来的“值”,而非我们实际的参数。

    改一下我们的目标,交换两个对象,照搬上面的模式:
        void swap(Object a, Object b) {
            Object temp = a;
            a = b;
            b = temp;
        }
    这个方法可以正常执行吗?这是一个比较让初学者糊涂的问题。乍看之下,对象传递过来的是引用(pass by reference),改变引用的结果应该可以作用到外部。实际上,调用这个函数前后,作为实际参数的对象不会有任何改变,也就是说,这只是一个浪费时间的方法。这种pass by reference实际上也是一种pass by value,不同的是,这里的value是reference而已。所以,对传入的reference重新赋值只是对副本进行操作,而本尊没有受到任何影响。

    设计方法的时候,大多数的参数是作为IN参数出现,也就是向方法传入一个值,但有时候,我们也需要参数作OUT参数——从方法内取回一个值,就像前面swap希望做的那样。如果你了解IDL(Interface Definition Language)的话,这些内容应该会让你有一丝亲切感。

    在C++中,如果希望一个参数作为OUT参数,我们可能会想到指针和引用。为了让调用代码少写几个‘&’,我们可能会选择引用。
        void swap(int &a, int &b) {
            int temp = a;
            a = b;
            b = temp;
        }

    但到了Java中,面对这样简单的一个需求,我们却很难通过最简单的方式完成,原因上面已经说得很清楚了。难道我们只能束手就擒了吗?显然不是。虽然我们不能把引用如何,但我们仍然可以对引用指向的内容痛下狠手,于是有了这样的解决方案,提供一个对象封装类,简单起见,这里把内部成员置成了public:
        class ObjectHolder {
            public Object object;
        }

    用它改写我们的swap:
        void swap(ObjectHolder a, ObjectHolder b) {
            Object temp = a.object;
            a.object = b.object;
            b.object = temp;
        }

    不过调用端代码会显得复杂许多,需要把对象封装到ObjectHolder,这样执行完swap之后,ObjectHolder中所放的对象便已经是修改之后的对象。若要原有对象也受到影响,那还需要把ObjectHolder的值取出,重新给原有对象赋值。Apache的Axis就是用这种方案解决了OUT参数的问题。

    Java语言从C++简化而来,一切本着简单的原则,但有些地方实在也太简单了,这样造成的结果就是有时为了完成一个简单的功能而绕很大的弯子。正是因为这样,Java语言这些年才会处于一个不断发展的过程中。也许等Java趋于完整的那一天,恐怕没有人会再以简单形容它了。

    分享到:

    历史上的今天:

    我们很忙 2009-11-08
    引用地址:

    评论

  • 用Integer不行吗?
  • 这个……的确是太简单了些。
    回复aero说:
    从语言的角度的来说,这个的确简单了一些,关键看你站在怎样的角度去理解这个问题。了解语言的优势与缺陷,可以更好提高自己对编程的理解。
    2004-11-09 16:39:40