按价值调用与按参考调用的呼叫与通过共享调用

时间:2016-06-23 21:27:04

标签: java parameter-passing

我试图理解Java中的参数传递。 Stackoverflow上有一些答案,但不清楚。 Evaluation Strategy页面非常具有技术性,因此我对此并不了解。这个答案很有帮助,但我不明白其含义:Is Java “pass-by-reference” or “pass-by-value”?

我理解Java使用Call by Sharing,但我不确定它与Call by Reference的区别。我不确定这是否正确,你能查看我的答案吗?

共享步骤
1)主程序调用一个方法并传递一个参数 2)评估参数中的表达式并确定其类型。结果将分配给Argument变量。

按值调用

3)不考虑类型,制作参数值的COPY并传递给方法。
4)形式参数接收包含参数COPY的变量 5)正式论证对副本进行更改 6)实际论点是不变的。

按参考号召集
3)不考虑类型,制作论证的地址的COPY并传递给该方法。 4)形式参数接收参数的存储位置的参考 5)Formal Argument和Actual Argument指向相同的值。两者都可以修改值/对象 6)方法可以在不受限制的情况下改变形式参数。当方法结束时,这些更改将在参数中看到。

通过共享呼叫(Java)
3)不考虑类型,进行参数地址的复制并传递给方法。
4)?
5)?
6)?

我知道Java在参数传递中如何处理原始类型和对象之间存在差异,有人可以通过解释原因填写这些空白吗?

2 个答案:

答案 0 :(得分:1)

按值调用表示

  • 在调用方法之前评估参数
  • 该方法收到此评估结果的副本
  • 通过方法应用于形式参数的更改对调用者不可见

按参考呼叫意味着

  • 在调用方法之前评估参数
  • 该方法收到参考到此评估结果
  • 通过方法应用于形式参数的更改对调用方可见

现在,我将跳过“分享呼叫”,因为它没有明确的含义。

它如何在Java中工作

  • 在调用方法之前评估参数
  • 该方法收到此评估结果的副本
  • 通过方法应用于形式参数的更改对调用者不可见

如您所见,Java匹配Call by Value案例。但是,要真正理解这一点,您必须了解Java如何处理引用。为此,请考虑此课程

public class Foo {
    private String value;

    public Foo(String value) {
        this.value = value;
    }

    public String get() {
        return value;
    }

    public void set(String value) {
        this.value = value;
    }
}

和此代码段:

Foo actual = new Foo("foo");      // 1
                                  // 2
Foo formal = actual;              // 3
    formal.set("bar");            // 4
                                  // 5
actual.get(); // returns "bar"    // 6

如您所见,formal中对象的更改已应用于actual中的对象,因为formal指向与actual相同的对象。赋值Foo formal = actual;确实复制了引用,它没有复制对象。

现在,让我们看看另一个代码示例:

Foo actual = new Foo("foo");      // 1
                                  // 2
Foo formal = actual;              // 3
    formal = new Foo("bar");      // 4
                                  // 5
actual.get(); // returns "foo"    // 6

正如您所看到的,对formal的更改尚未应用于actual,因为formal中指向actual中对象的引用已被覆盖通过引用一个新对象。赋值Foo formal = actual;确实复制了引用,它没有将指针复制到actual

现在,我谈到了作业,因为我认为作业非常明确。现在的观点是,这与方法调用的行为完全相同:调用方法时,将计算出的实际参数赋值给形式参数,参见第3行。但是,形式参数在方法完成后分配回实际参数,参见第5行。

这称为“共享呼叫”的原因是,您没有传递实际参数的深层副本。因此,在调用者和被调用者之间共享对象。如果对象包含可变状态(如Foo),则调用方可以看到应用于方法中该可变状态的所有更改。请注意区别:传递的对象的更改是可见的,更改正式参数的参考目标是不可见的。

最后,关于基元的快速说明:上面的代码不需要为基元更改。这意味着,只有类型Foo才会更改为boolean。其他一切都是一样的。因此,行为再次与赋值相同:复制该值。由于原始值不能包含可变状态,因此毫无疑问这是Call by Value。

答案 1 :(得分:-1)

我理解Call By Sharing是这样的:

使用Value类型,直接复制实际值,并将新副本传递给被调用者。原始值无法修改。

使用引用类型,将复制对值的实际引用,并将新副本传递给被调用者。可以修改引用的对象,但重新分配不会修改原始引用。

如果使用传递的引用重新分配,则在callee中创建一个新对象,返回调用者将反映最初传递的对象。在被调用者中创建的对象应该超出范围并标记为收集。