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

什么是解释?


当前回答

Java 通过原始类型为值和类型为参考

现在,人们喜欢无限地争论是否“通过参考”是正确的方式来描述Java et al. 实际上做什么。

通过一个对象不会复制对象,转移到函数的对象可以由函数修改其成员,转移到函数的原始值不能由函数修改。

在我的书中,它被称为通过参考。

布莱恩·比(Brian Bi) - 哪种编程语言通过参考?

其他回答

Java 按值传输参考。

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

“pass-by-value”和“pass-by-reference”是指变量;“pass-by-value”是指变量的值转移到函数/方法;“pass-by-reference”是指该变量的参考转移到函数;“pass-by-reference”是指变量的值转移到函数;“pass-by-reference”是指变量的值转移到函数。

它如同这样:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    Dog oldDog = aDog;

    // we pass the object to foo
    foo(aDog);
    // aDog variable is still pointing to the "Max" dog when foo(...) returns
    aDog.getName().equals("Max"); // true
    aDog.getName().equals("Fifi"); // false
    aDog == oldDog; // true
}

public static void foo(Dog d) {
    d.getName().equals("Max"); // true
    // change d inside of foo() to point to a new Dog instance "Fifi"
    d = new Dog("Fifi");
    d.getName().equals("Fifi"); // true
}

同样:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    Dog oldDog = aDog;

    foo(aDog);
    // when foo(...) returns, the name of the dog has been changed to "Fifi"
    aDog.getName().equals("Fifi"); // true
    // but it is still the same dog:
    aDog == oldDog; // true
}

public static void foo(Dog d) {
    d.getName().equals("Max"); // true
    // this changes the name of d to be "Fifi"
    d.setName("Fifi");
}

有关参考通行和值通行的更多信息,请参见以下答案: https://stackoverflow.com/a/430958/6005228. 这更详细地解释了两者背后的语法和历史,并解释了为什么Java和许多其他现代语言似乎在某些情况下都会做两件事。

经过全面的讨论,我认为现在是时候将所有严重的结果聚集在一起。

/**
 * 
 * @author Sam Ginrich
 * 
 * All Rights Reserved!
 * 
 */
public class JavaIsPassByValue
{

    static class SomeClass
    {
        int someValue;

        public SomeClass(int someValue)
        {
            this.someValue = someValue;
        }
    }

    static void passReferenceByValue(SomeClass someObject)
    {
        if (someObject == null)
        {
            throw new NullPointerException(
                    "This Object Reference was passed by Value,\r\n   that's why you don't get a value from it.");
        }
        someObject.someValue = 49;
    }

    public static void main(String[] args)
    {
        SomeClass someObject = new SomeClass(27);
        System.out.println("Here is the original value: " + someObject.someValue);

        passReferenceByValue(someObject);
        System.out.println(
                "\nAs ´Java is pass by value´,\r\n   everything without exception is passed by value\r\n   and so an object's attribute cannot change: "
                    + someObject.someValue);

        System.out.println();
        passReferenceByValue(null);
    }

) )

从输出中可以很容易地看到,在Java中,一切都通过价值,如此简单!

Here is the original value: 27

As ´Java is pass by value´,
   everything without exception is passed by value
   and so an object´s attribute cannot change: 49

'Exception in thread "main" java.lang.NullPointerException: This Object Reference was passed by value,
   that´s why you don´t get a value from it. 
    at JavaIsPassByValue.passReferenceByValue(JavaIsPassByValue.java:26)
    at JavaIsPassByValue.main(JavaIsPassByValue.java:43)

Java,当然,毫无疑问,是“通过价值”。 此外,由于Java是(主要)对象导向和对象与参考工作,它很容易被困惑,并认为它是“通过参考”

但要测试它是否真的通过值或通过参考,你可以使用原始类型和参考:

@Test
public void sampleTest(){
    int i = 5;
    incrementBy100(i);
    System.out.println("passed ==> "+ i);
    Integer j = new Integer(5);
    incrementBy100(j);
    System.out.println("passed ==> "+ j);
}
/**
 * @param i
 */
private void incrementBy100(int i) {
    i += 100;
    System.out.println("incremented = "+ i);
}

产量是:

incremented = 105
passed ==> 5
incremented = 105
passed ==> 5

因此,在两种情况下,任何在方法中发生的事情都不会改变真正的对象,因为对象的价值已经过去了,而不是对象本身的参考。

但是,当你将自定义对象转移到一种方法,而一种方法并改变它时,它也会改变真正的对象,因为即使你通过了对象,你也将其参考作为一种价值转移到一种方法。

@Test
public void sampleTest2(){
    Person person = new Person(24, "John");
    System.out.println(person);
    alterPerson(person);
    System.out.println(person);
}

/**
 * @param person
 */
private void alterPerson(Person person) {
    person.setAge(45);
    Person altered = person;
    altered.setName("Tom");
}

private static class Person{
    private int age;
    private String name; 

    public Person(int age, String name) {
        this.age=age;
        this.name =name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Person [age=");
        builder.append(age);
        builder.append(", name=");
        builder.append(name);
        builder.append("]");
        return builder.toString();
    }

}

在这种情况下,产量是:

Person [age=24, name=John]
Person [age=45, name=Tom]

我从一本关于Java认证的书中取了这个代码和解释,并做了一些小变化,我认为这是一个很好的图像,通过对象的价值。在下面的代码中,重新分配g不会重新分配f!在条()方法的结尾,创建了两个Foo对象,一个是由当地变量f和一个是由当地(论点)变量g提到的。

package test.abc;

public class TestObject {

    /**
     * @param args
     */
    public static void main(String[] args) {
        bar();
    }

    static void bar() {
        Foo f = new Foo();
        System.out.println("Object reference for f: " + f);
        f.setName("James");
        doStuff(f);
        System.out.println(f.getName());
        //Can change the state of an object variable in f, but can't change the object reference for f.
        //You still have 2 foo objects.
        System.out.println("Object reference for f: " + f);
        }

    static void doStuff(Foo g) {
            g.setName("Boo");
            g = new Foo();
            System.out.println("Object reference for g: " + g);
        }
}


package test.abc;

public class Foo {
    public String name = "";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

对象参考 f: test.abc.Foo@62f72617