我一直以为Java使用pass-by-reference. 但是,我读了一篇博客文章,声称Java使用pass-by-value. 我不认为我明白作者所做的区别。

什么是解释?


当前回答

Java 按值传输参考。

因此,你不能改变通过的参考。

其他回答

Java 总是使用 Call by Value. 这意味着该方法获得所有参数值的副本。

考虑下列三种情况:

1、试图改变原始变量

public static void increment(int x) { x++; }

int a = 3;
increment(a);

x 将复制一个值,并将增加 x,一个将保持相同的值

(二)试图改变对象的原始领域

public static void increment(Person p) { p.age++; }

Person pers = new Person(20); // age = 20
increment(pers);

p 将复制个体的参考值,并将增加年龄领域,变量是指相同的对象,所以年龄改变。

(三)试图改变参考变量的参考值

public static void swap(Person p1, Person p2) {
    Person temp = p1;
    p1 = p2;
    p2 = temp;
}

Person pers1 = new Person(10);
Person pers2 = new Person(20);
swap(pers1, pers2);

呼叫交换 p1 后,p2 复制 pers1 和 pers2 的参考值与值交换,因此 pers1 和 pers2 仍然相同。

因此,您只能在将参考值复制到该对象时更改对象的字段。

很难理解,但Java总是复制值 - 点是,通常值是参考。

在我所知道的范围内,Java只知道值的呼叫,这意味着对于原始数据类型,您将使用复印件工作,对于对象,您将使用对象的参考复印件工作。

public static void swap(StringBuffer s1, StringBuffer s2) {
    StringBuffer temp = s1;
    s1 = s2;
    s2 = temp;
}


public static void main(String[] args) {
    StringBuffer s1 = new StringBuffer("Hello");
    StringBuffer s2 = new StringBuffer("World");
    swap(s1, s2);
    System.out.println(s1);
    System.out.println(s2);
}

这将人口Hello World而不是World Hello,因为在交换函数中,您使用复印件,这些复印件不会对主要的参考产生影响。

public static void appendWorld(StringBuffer s1) {
    s1.append(" World");
}

public static void main(String[] args) {
    StringBuffer s = new StringBuffer("Hello");
    appendWorld(s);
    System.out.println(s);
}

如果您将 StringBuffer 更改为 String,它只会产生 Hello 因为 String 是不可变的。

public static void appendWorld(String s){
    s = s+" World";
}

public static void main(String[] args) {
    String s = new String("Hello");
    appendWorld(s);
    System.out.println(s);
}

但是,你可以为 String 做一个插槽,这将使它能够与 Strings 一起使用:

class StringWrapper {
    public String value;

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

public static void appendWorld(StringWrapper s){
    s.value = s.value +" World";
}

public static void main(String[] args) {
    StringWrapper s = new StringWrapper("Hello");
    appendWorld(s);
    System.out.println(s.value);
}

编辑:我认为这也是使用 StringBuffer 的理由,当涉及到“添加”两个线条时,因为你可以修改原始对象,你不能用像 String 这样的不可变的对象。

参考是常见的值,无论你使用哪种语言。

(Name)[Location] -> [Value at the Location]
---------------------
(Ref2Foo)[223]  -> 47
(Foo)[47]       -> 5

这就是跳板的工作方式。

在每个例子上创建了一个值 - 一个现有值的副本 - 现在是接收方法来处理它. 当你写“Foo”在方法,它是从EAX,或者自动右转,或双右转,过程取决于语言如何工作和 / 或什么类型的Foo独裁。

现在我们把Foo转到方法:

因此,简而言之,在Java本身的术语中,Java是通过价值,在那里价值可以是:无论是真实的价值还是参考的价值。

首先,通过参考与通过价值之间的区别是什么?

关于 pass-by-value 的评论

在 call-by-value 中,论点表达是评估的,结果值与函数中的相应变量有联系......如果函数或程序能够将值分配给其参数,则仅会分配其本地副本。

因此,它分配(或绑定)论点的价值与相应的参数变量。

论点的价值是什么?

Java 语言规格也表示

public void method (String param) {}
...
String variable = new String("ref");
method(variable);
method(variable.toString());
method(new String("ref"));

一切都将一个参考的值绑在一个紧缩例子上,该方法的新创建的参数,参数,这正是通过值的定义所描述的。