Java是“通过引用传递”还是“按值传递”?

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

什么是解释?

  1. 我相信在这个问题上的混淆很大程度上与不同的人对“参考”这个词有不同的定义。来自C ++背景的人认为“参考”一定意味着在C ++中意味着什么,来自C背景的人们假定“参考”必须与其语言中的“指针”相同,等等。说Java通过引用传递是否正确取决于“引用”是什么意思。
  2. 我试图始终如一地使用评估策略文章中的术语。应该指出的是,尽管文章指出社区的条款差异很大,但它强调语义call-by-valuecall-by-reference差异是非常关键的。(我个人更喜欢使用call-by-object-sharing这些日子call-by-value[-of-the-reference],因为这描述了高层次的语义,并没有产生冲突call-by-value,这潜在的实现。)
  3. 你能把你的评论放在一个巨大的广告牌上吗?这就是整个问题。这表明这整个事情是语义。如果我们不同意参考的基本定义,那么我们不会同意这个问题的答案:)
  4. 我宁愿问是否在调用时复制传递给方法的值。我想这是你正在寻找的问题。
  5. 我认为混淆是“通过引用”与“引用语义”。Java是通过引用语义传递值的。

 

答案一:

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

它是这样的:

public static void main( String[ ] args ) {
    Dog aDog = new Dog("Max");<span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_start"></span>
    // 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"。值aDogmain未在功能改变fooDog "Fifi"作为对象基准由值来传递。如果通过引用传递,那么aDog.getName()在调用之后,in main将返回。"Fifi"foo

同样:

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(...)foodaDogdDogd = new Dog("Boxer")

答案二:

 

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

Java Spec说,Java中的所有东西都是按值传递的。Java中没有“传引用”的东西。

理解这个关键就是这样的

Dog myDog;

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

这意味着什么,当你有

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

你基本上是将创建的对象的地址传递Dogfoo方法。

(我之所以说,本质上是因为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(地址42的那个)被要求将他的名字改为Max
  • 在“BBB”行
    • 一个新Dog的创建。假设他在地址74
    • 我们将参数分配someDog给74
  • 在“CCC”行
    • someDog跟着Dog它指向(Dog地址为74 的对象)
    • Dog(地址为74的那个)被要求将他的名字改为Rowlf
  • 那么,我们回来

现在让我们考虑一下在这个方法之外发生的事情:

myDog改变吗?

有关键。

记住这myDog是一个指针,而不是实际的Dog,答案是否定的。myDog仍然有价值42; 它仍然指向原来的Dog(但注意,由于“AAA”行,它的名字现在是“最大” – 仍然相同的狗myDog的价值没有改变。)

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

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

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

如果Java具有引用传递语义,那么foo我们在上面定义的方法将在BBB上myDog分配的位置发生改变someDog

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

添加评论

友情链接:蝴蝶教程