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

什么是解释?


当前回答

我们有2个不同的术语(Call-by-Value/Call-by-Reference)但至少有3(!)不同的方式处理上述数据,当将其转移到一个方法:

我们的数据是复制的,复制加到一个方法. 复制的变化不会在外面传播.(想想一个 int 在 Java 或 C++ 或 C#.) 一个指标(记忆地址)我们的数据加到方法而不是. 我们的数据的变化加到外面传播. 我们也可以指向一些新的例子,让我们的原始数据危害。

在 OO 世界中, #1 是 Call-by-Value 和 #2 是 Call-by-Reference. 但是,由于我们只有两个条件为三个选项,没有两个条件之间的明确定义,由于选项 #3 。

“为什么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和许多其他现代语言似乎在某些情况下都会做两件事。

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 仍然相同。

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

public void foo(Object param)
{
  // some code in foo...
}

public void bar()
{
  Object obj = new Object();

  foo(obj);
}

它是相同的......

public void bar()
{
  Object obj = new Object();

  Object param = obj;

  // some code in foo...
}

不要考虑在这个讨论中不相关的站点。

你会遇到的最常见的运营商之一是简单的任务运营商“="......它将其右上的值归分为其左上的运营商: int cadence = 0; int speed = 0; int gear = 1; 这个运营商也可以用于对象归分对象参考。

很明显,这个运营商如何以两种不同的方式行动:分配值和分配参考;最后,当它是一个对象......第一,当它不是一个对象,即当它是一个原始的。

真相在代码中,让我们尝试一下:

public class AssignmentEvaluation
{
  static public class MyInteger
  {
    public int value = 0;
  }

  static public void main(String[] args)
  {
    System.out.println("Assignment operator evaluation using two MyInteger objects named height and width\n");

    MyInteger height = new MyInteger();
    MyInteger width  = new MyInteger();

    System.out.println("[1] Assign distinct integers to height and width values");

    height.value = 9;
    width.value  = 1;

    System.out.println("->  height is " + height.value + " and width is " + width.value + ", we are different things! \n");

    System.out.println("[2] Assign to height's value the width's value");

    height.value = width.value;

    System.out.println("->  height is " + height.value + " and width is " + width.value + ", are we the same thing now? \n");

    System.out.println("[3] Assign to height's value an integer other than width's value");

    height.value = 9;

    System.out.println("->  height is " + height.value + " and width is " + width.value + ", we are different things yet! \n");

    System.out.println("[4] Assign to height the width object");

    height = width;

    System.out.println("->  height is " + height.value + " and width is " + width.value + ", are we the same thing now? \n");

    System.out.println("[5] Assign to height's value an integer other than width's value");

    height.value = 9;

    System.out.println("->  height is " + height.value + " and width is " + width.value + ", we are the same thing now! \n");

    System.out.println("[6] Assign to height a new MyInteger and an integer other than width's value");

    height = new MyInteger();
    height.value = 1;

    System.out.println("->  height is " + height.value + " and width is " + width.value + ", we are different things again! \n");
  }
}

这就是我跑步的结果:

Assignment operator evaluation using two MyInteger objects named height and width

[1] Assign distinct integers to height and width values
->  height is 9 and width is 1, we are different things! 

[2] Assign to height's value the width's value
->  height is 1 and width is 1, are we the same thing now? 

[3] Assign to height's value an integer other than width's value
->  height is 9 and width is 1, we are different things yet! 

[4] Assign to height the width object
->  height is 1 and width is 1, are we the same thing now? 

[5] Assign to height's value an integer other than width's value
->  height is 9 and width is 9, we are the same thing now! 

[6] Assign to height a new MyInteger and an integer other than width's value
->  height is 1 and width is 9, we are different things again! 

我们不能那么确定,因为在 [6] 对象是相同的,然后我们将一个新的对象归分给其中一个,然后,对象有不同的价值! 他们现在如何区分,如果他们是相同的? 他们应该在这里也是相同的!!!

此操作员也可以用于对象分配对象参考。

查看此代码. 此代码不会扔 NullPointerException... 它将打印“Vinay”

public class Main {
    public static void main(String[] args) {
        String temp = "Vinay";
        print(temp);
        System.err.println(temp);
    }

    private static void print(String temp) {
        temp = null;
    }
}

如果 Java 通过参考,则应该将 NullPointerException 扔下来,因为参考设置为 Null。

我遇到了类似的问题. 这个关于圈子的故事对我来说是一个具体的答案. 我想添加到答案. 希望它能帮助那些有类似问题的人。

https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html

在方法中,循环起初指 myCircle. 该方法改变了对象的 x 和 y 坐标,循环参考(即 myCircle)为 23 和 56, 相应. 这些变化将持续,当方法返回. 然后循环被分配一个参考一个新的循环对象与 x = y = 0. 这个重新分配没有永久性, 但是,因为参考通过了值