是Java“通过

我一直认为Java是通过引用 。 不过,我见过一些博客文章(例如,这个博客),声称它不是。 我不认为我理解他们的区别。

什么是解释?


Java始终是按值传递的 。 不幸的是,他们决定将对象的位置称为“参考”。 当我们传递一个对象的值时,我们将引用传递给它。 这对初学者来说很混乱。

它是这样的:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    // 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, java passes by value
    aDog.getName().equals("Fifi"); // false 
}

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" 。 在函数fooDog "Fifi"没有改变main的值aDog ,因为对象引用是按值传递的。 如果它通过引用传递,那么在调用foo之后, mainaDog.getName()将返回"Fifi"

同样:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    foo(aDog);
    // when foo(...) returns, the name of the dog has been changed to "Fifi"
    aDog.getName().equals("Fifi"); // true
}

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

在上面的例子中, Fifi是调用foo(aDog)之后的狗的名字,因为该对象的名字是在foo(...) 。 任何food上执行的操作都是这样的,为了所有实际目的,它们都是在aDog本身上执行的(除非将d更改为指向不同的Dog实例,如d = new Dog("Boxer") )。


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

Java Spec说,Java中的所有东西都是按值传递的。 Java中没有“传递参考”这样的东西。

理解这一点的关键是类似的东西

Dog myDog;

不是狗; 它实际上是一个指向狗的指针。

这意味着什么,当你有

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
}

让我们看看发生了什么。

  • 参数someDog被设置为值42
  • 在“AAA”行
  • someDog Dog跟随它指向的Dog (地址42处的Dog对象)
  • Dog (地址42处的Dog )被要求将他的名字改为Max
  • 在“BBB”行
  • 一个新的Dog被创建。 假设他在地址74
  • 我们将参数someDog分配给74
  • 在“CCC”行
  • 有些Dog跟随它指向的Dog (地址为74的Dog对象)
  • Dog (地址为74的那个)被要求将他的名字改为Rowlf
  • 那么,我们回来
  • 现在让我们考虑一下在该方法之外发生的事情:

    myDog是否改变了?

    有关键。

    记住myDog是一个指针,而不是真正的Dog ,答案是NO。 myDog仍然有值42; 它仍然指向原来的Dog (但请注意,因为“AAA”行,它的名字现在是“最大” - 仍然是狗; myDog的值没有改变。)

    遵循地址并改变结尾是完全有效的; 但不会改变变量。

    Java的工作方式与C完全一样。您可以指定一个指针,将指针传递给方法,跟随方法中的指针并更改指向的数据。 但是,您无法更改指针指向的位置。

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

    要是Java传递by-reference语义中, foo我们在上面定义的方法会改变其中myDog指着时分配someDog上线BBB。

    将引用参数看作是传入变量的别名。当分配了别名时,传入的变量也是如此。


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

    我将逐步解释这一点:

  • 声明一个名为fFoo类型的引用,并将其赋值给一个具有属性"f" Foo类型的新对象。

    Foo f = new Foo("f");
    

  • 在方法方面,声明了一个名为a Foo类型的引用,并且它的初始null

    public static void changeReference(Foo a)
    

  • 在调用方法changeReference ,引用a将被分配给作为参数传递的对象。

    changeReference(f);
    

  • 声明一个名为bFoo类型的引用,并将其赋值给一个具有属性"b" Foo类型的新对象。

    Foo b = new Foo("b");
    

  • a = b将引用a NOT f重新分配给其属性为"b"的对象。


  • 当您调用modifyReference(Foo c)方法时,会创建一个引用c并将其分配给具有属性"f"的对象。

  • c.setAttribute("c"); 将改变引用c点的对象的属性,并且引用f指向它的是同一个对象。

  • 我希望你现在能理解如何将对象作为参数传递给Java。

    链接地址: http://www.djcxy.com/p/49.html

    上一篇: Is Java "pass

    下一篇: Can comments be used in JSON?