当前位置: 首页 > 知识库问答 >
问题:

Java是“按参考传递”还是“按价值传递”?

锺离刚洁
2023-03-14

我一直认为Java使用按引用传递。

然而,我看到一篇博客文章声称Java使用传递值。

我想我不明白他们的区别。

原因是什么?

共有3个答案

陈修诚
2023-03-14

Java总是通过值传递参数,而不是通过引用。

让我通过一个例子来解释这一点:

public class Main {

     public static void main(String[] args) {
          Foo f = new Foo("f");
          changeReference(f); // It won't change the reference!
          modifyReference(f); // It will modify the object that the reference variable "f" refers to!
     }

     public static void changeReference(Foo a) {
          Foo b = new Foo("b");
          a = b;
     }

     public static void modifyReference(Foo c) {
          c.setAttribute("c");
     }

}

我将分步骤解释这一点:

>

  • 声明类型为Foo的名为f的引用,并为其分配一个类型为Foo的新对象,该对象具有属性“f”

    Foo f = new Foo("f");
    

    从方法方面,声明了一个名为aFoo类型的引用,并将其初始赋值为null

    public static void changeReference(Foo a)
    

    调用方法changeReference时,引用a将被指定作为参数传递的对象。

    changeReference(f);
    

    声明一个名为bFoo类型的引用,并为其分配一个Foo类型的新对象,该对象具有属性“b”

    Foo b = new Foo("b");
    

    a=b对属性为“b”的对象的引用a,而不是f,进行新赋值。

    当您调用modifyReference(Foo c)方法时,将创建一个引用c,并为该对象分配属性“f”

    c.setAttribute(“c”)将更改引用c指向它的对象的属性,并且它是引用f指向它的同一个对象。

    我希望您现在了解了在Java中作为参数传递对象的工作原理:)

  • 太叔高义
    2023-03-14

    我刚注意到你引用了我的文章。

    Java规范说Java中的一切都是按价值传递的。在Java中不存在所谓的“通过引用”。

    理解这一点的关键是

    Dog myDog;
    

    不是狗;它实际上是指向狗的指针。在Java中使用“参考”一词是非常误导的,也是造成这里大部分混乱的原因。他们所说的“引用”的行为/感觉更像我们在大多数其他语言中所说的“指针”。

    这意味着,当你

    Dog myDog = new Dog("Rover");
    foo(myDog);
    

    实际上,您将创建的Dog对象的地址传递给foo方法。

    (我之所以这么说,主要是因为Java指针/引用不是直接地址,但最容易这样想。)

    假设Dog对象位于内存地址42。这意味着我们将42传递给方法。

    如果方法定义为

    public void foo(Dog someDog) {
        someDog.setName("Max");     // AAA
        someDog = new Dog("Fifi");  // BBB
        someDog.setName("Rowlf");   // CCC
    }
    

    让我们看看发生了什么。

    • 的参数某些狗设置为值42
    • 在AAA行
        后面跟着它指向的(地址42处的对象)
      • 狗(地址42的那个)被要求把他的名字改成马克斯
      • 一个新的Dog被创建。假设他在74号地址
      • 我们将参数某些狗赋值给74
      • 后面跟着的是它指向的Dog(地址74的Dog对象)
      • 狗(地址74的那个)被要求把他的名字改成罗尔夫

      现在让我们考虑一下在方法之外会发生什么:

      myDog有变化吗?

      这是钥匙。

      请记住,myDog是指针,而不是实际的Dog,答案是否定的。myDog仍然具有值42;它仍然指向原始的Dog(但是请注意,由于行“AAA”,它的名称现在是“Max”-仍然是同一只狗;myDog的值没有改变。)

      跟随地址并更改地址末尾的内容是完全有效的;但是,这不会改变变量。

      Java的工作原理与C完全相同。您可以分配一个指针,将指针传递给一个方法,跟随方法中的指针,并更改指向的数据。但是,调用方将看不到您对指针指向的位置所做的任何更改。(在具有按引用传递语义的语言中,方法函数可以更改指针,调用方将看到该更改。)

      在C、Ada、Pascal和其他支持按引用传递的语言中,实际上可以更改传递的变量。

      如果Java有通过引用的语义学,我们上面定义的foo方法将改变myDog指向的位置,当它在行BBB上分配某些狗时。

      将引用参数视为传入变量的别名。分配该别名时,传入的变量也是如此。

    司空元凯
    2023-03-14

    Java总是按价值传递的。不幸的是,当我们处理对象时,我们实际上是在处理被称为引用的对象句柄,这些句柄也是按值传递的。这个术语和语义学很容易让很多初学者混淆。

    事情是这样的:

    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
    }
    

    在上面的例子中,aDog。getName()仍将返回“Max”main中的值aDog在函数foo中不会随Dog“Fifi”而改变,因为对象引用是通过值传递的。如果通过引用传递,则aDog。调用foo后,main中的getName()将返回“fififi”

    同样地:

    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");
    }
    

    在上面的例子中,菲菲是调用foo(aDog)后的狗的名字,因为对象的名字设置在foo(...)内。任何food上执行的操作,出于所有实际目的,都是在aDog上执行的,但是不可能更改变量aDog本身的值。

    有关传递参考和传递值的更多信息,请参考以下答案:https://stackoverflow.com/a/430958/6005228.这更透彻地解释了这两种语言背后的语义和历史,也解释了为什么Java和许多其他现代语言在某些情况下似乎同时使用这两种语言。

     类似资料:
    • 问题内容: 我一直认为Java使用传递引用。 但是,我已经看到了几篇博客文章声称不是(博客文章说Java使用值传递)。 我不认为我能理解他们的区别。 有什么解释? 问题答案: Java总是按值传递。 不幸的是,我们根本不处理任何对象,而是处理称为引用的 对象句柄(当然是通过值传递)。选择的术语和语义很容易使许多初学者感到困惑。 它是这样的: 在上面的示例中仍将返回”Max”。值aDog内main未

    • 本文向大家介绍JS是按值传递还是按引用传递,包括了JS是按值传递还是按引用传递的使用技巧和注意事项,需要的朋友参考一下 按值传递 VS. 按引用传递 按值传递(call by value)是最常用的求值策略:函数的形参是被调用时所传实参的副本。修改形参的值并不会影响实参。   按引用传递(call by reference)时,函数的形参接收实参的隐式引用,而不再是副本。这意味着函数形参的值如果被

    • 问题内容: 我读了许多文章,都说Java是通过价值传递的。但是我仍然不能解释按值传递和引用之间的区别。我写了一个示例程序,它像这样执行。 执行 谁能向我解释这些问题… 价值传递是什么意思? 答:它只是将存储在变量中的数字或值传递给函数。我是对还是错。 How do you say Java是通过价值传递? 为什么Java是按值传递而不是按引用传递? 上面的程序Tries是否显示了“按值传递”和“引

    • 问题内容: 基本类型(数字,字符串等)按值传递,但对象未知,因为它们都可以按值传递(如果我们认为保存对象的变量实际上是对该对象的引用) )和按引用传递(当我们认为对象的变量包含对象本身时)。 尽管最后并没有什么大不了,但我想知道呈现通过惯例的参数的正确方法是什么。是否有JavaScript规范的摘录,其中定义了与此相关的语义? 问题答案: JavaScript很有趣。考虑以下示例: 产生输出: 如

    • 问题内容: 如果我将数据帧传递给函数并在函数内部对其进行修改,那么它是按值传递还是按引用传递? 我运行以下代码 函数调用后,的值不变。这是否意味着价值传递? 我也尝试了以下 事实证明,变化并没有。为什么会这样呢? 问题答案: 简短的答案是,Python始终会传递值,但每个Python变量实际上都是指向某个对象的指针,因此有时看起来像是传递引用。 在Python中,每个对象都是可变的或不可更改的。例

    • 我创建了一个MapReduce作业,该作业将计算键的数量,然后根据它们出现的次数对它们进行排序 处理输入时,如 最终目标将是一个类似于 我的地图阶段输出a 我的减少阶段有3个阶段:设置,我初始化一个数组列表来保存我的 数组列表中的值是我创建的一个对象myObject的值,它将文本和Int保存在一个元组中可写,我发现一个奇怪的地方是当我这样做的时候 key是传递到reducer的键,count是我通