通过引用呼叫或按值呼叫

时间:2013-08-13 15:31:26

标签: java static-methods pass-by-reference call-by-value

有人可以解释一下这个程序是如何执行的吗?

这是代码,其输出我似乎无法得到它:

    class Box {
        int size;
        Box (int s) {
           size = s;
        }
    }
    public class Laser {
        public static void main(String[] args) {
            Box b1 = new Box(5);
            Box[] ba = go(b1, new Box(6));
            ba[0] = b1;
            for(Box b : ba)
                System.out.println(b.size + " ");
        }

        static Box[] go (Box b1, Box b2) {
            b1.size = 4;
            Box[] ma = {b2, b1};
            return ma;
        }
    }

我运行时的实际输出是4,4。但根据我的理解,这应该是5,4。 任何人都可以帮助了解这是如何执行的?

7 个答案:

答案 0 :(得分:3)

我已为您添加了评论;

The important TWIST that you missed here is;

Box[] ma = {b2, b1};不是{b1,b2}。返回时内存位置互换。

       public static void main(String[] args) {
            Box b1 = new Box(5);                 // b1 == location A
            Box[] ba = go(b1, new Box(6));       // ba == location B which stores Location A, D

           // PLEASE NOTE HERE
           // After the function go() is executed;
           // ba[] will have {D, A}
           // So ba[0] will have object b1 which is at location A. 

            ba[0] = b1;                          // location B will now store A and A
            for(Box b : ba)
                System.out.println(b.size + " ");  //  Output: 4 and 4
        } 

        static Box[] go (Box b1, Box b2) {        // go(location A, location D )
            b1.size = 4;                          // A's object.size = 4
            Box[] ma = {b2, b1};                  // position is interchanged here (D and A)
            return ma;                            // return the location of ma
        }

希望这会有所帮助。

如果您有任何疑问,请告诉我。一切都是在java中传递的。内存地址按值传递。

答案 1 :(得分:0)

当您将对象作为参数传递时,实际上是将引用副本传递给它。也就是说,如果修改方法内的参数对象,该对象将在该方法返回时保留这些修改,这就是b1size = 4返回后保留go赋值的原因。

答案 2 :(得分:0)

Java总是在方法调用中传递对象的引用。当您致电go时,第一个参数(b1)是对您b1中相同的Box main的引用。然后,您可以修改该size现在为4的对象。

答案 3 :(得分:0)

传递给go的值是对象的引用。如果您来自C,您可以将参数视为具有指针类型,例如

Box** go (Box *b1, Box *b2) {
     b1->size = 4;
     /* allocate an array of Box*, set it up, return it */
}

(对不起,如果我的C语法错误。)指针(引用)本身是按值传递的,这意味着如果你在里面说“go”(在C程序中):

b1 = &some_other_box;

它不会影响调用端的任何变量,它在Java中的工作方式相同。这使得它与PHP或Pascal中的var参数略有不同。

答案 4 :(得分:0)

Java在方法调用中传递对象的引用副本。

您无法通过分配对象来更改对象。

public static void main(String[] args) {
    Box b1 = new Box(5);
    Change(b1);
    System.out.println(b1.size + " ");

static void Change(Box b1) {
    b1 = new Box(6);
}

这将始终返回5,因为函数Change仅将副本覆盖到引用的对象。

但是你可以像这样影响对象的属性:

public static void main(String[] args) {
    Box b1 = new Box(5);
    Change(b1);
    System.out.println(b1.size + " ");

static void Change(Box b1) {
    b1.size = 6;
}

这将返回6(对象的引用保持不变)。

答案 5 :(得分:0)

如果原始帖子中的'go'函数在C中(并且b1和b2是C指针),它可以执行以下两项操作(调用者将看到):

  1. 更改b1和b2指向的数据结构中的变量值。
  2. 使原始b1和b2指向不同的数据结构。
  3. 在Java中,我们可以做1但不是2,因为go无法访问原始的b1和b2。 (它可以访问b1和b2的副本。在子程序开始时,副本b1指向与原始b1相同的对象,依此类推。)

    说Java是逐个调用DOES错过的东西,即函数执行1的能力,即改变b1和b2引用的堆中对象的属性。 [这是声明中发生的事情,b1.size = 4;,这导致了原始海报的混乱。]

    'go'中的

    b1与'main'中的b1位置不同。但是,当函数开始时,'go'中的b1引用与'main'中的b1相同的对象,并且当'main'中的b1用作引用时,将看到使用'go'中的b1对对象所做的任何更改。

    但是,如果'go'中的b1设置为另一个Box,'main'中的b1将不会看到这个;它仍会看到前一个Box。

答案 6 :(得分:-1)

在Java中,对象通过引用传递,基元通过值传递。

public class Laser {
    public static void main(String[] args) {
        //Create a Box of size 5.
        Box b1 = new Box(5);
        //Create an array of Box objects, which are the results of the go method
        Box[] ba = go(b1, new Box(6));
        // ba now looks like {new Box(6), b1 /*b1 is size 4 now*/}
        // assign reference to b1 at index 0 in ba.
        ba[0] = b1;
        // array now looks like {b1, b1}
        for(Box b : ba)
            System.out.println(b.size + " ");
    }

    static Box[] go (Box b1, Box b2) {
        //set the size of the first box to 4
        b1.size = 4;
        //create an array of boxes, with b2 in index 0 and b1 in index 1
        Box[] ma = {b2, b1};
        return ma;
    }
}