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


我一直以为Java是 通过按引用

但是,我看过几篇博文(例如, 这个博客)声称它不是。

我不认为我理解他们所做的区别。

解释是什么?


5495


起源


我认为,在这个问题上的大部分混淆都与不同的人对“参考”一词有不同定义的事实有关。来自C ++背景的人认为“引用”必须意味着它在C ++中的含义,来自C背景的人认为“引用”必须与其语言中的“指针”相同,依此类推。说Java通过引用传递是否正确取决于“引用”的含义。 - Gravity
我尝试始终如一地使用在 评估策略 文章。应该指出的是,尽管文章指出这些术语因社区而异,但它仍然存在很大差异 强调语义为 call-by-value 和 call-by-reference 以非常关键的方式有所不同。 (我个人更喜欢使用 call-by-object-sharing 这些日子结束了 call-by-value[-of-the-reference],因为它描述了高级语义并且不会产生冲突 call-by-value, 哪一个 是 底层实现。)
@Gravity:你能把你的评论放在巨大的广告牌上吗?简而言之,这就是整个问题。它表明这一切都是语义学。如果我们不同意参考的基本定义,那么我们将不同意这个问题的答案:) - MadConan
我认为混淆是“通过引用传递”与“引用语义”。 Java是带引用语义的pass-by-value。 - spraff
@Gravity,而你 绝对 来自C ++的人会本能地对“参考”一词有不同的直觉设定,我个人认为身体更多地埋藏在“by”中。 “传递”令人困惑,因为它与Java中的“传递”完全不同。但是在C ++中,通俗地说不是。在C ++中,您可以说“传递引用”,它就是 明白它会通过 swap(x,y) 测试。


答案:


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
    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"。价值 aDog 中 main 在功能中没有改变 foo 随着 Dog  "Fifi" 因为对象引用是按值传递的。如果通过引用传递,那么 aDog.getName() 在 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(...)。任何操作 foo 执行 d 为了所有实际目的,它们都是这样的 aDog 本身(除非 d 被改为指向另一个 Dog 例如 d = new Dog("Boxer"))。


4741



这个问题与内部细节有点混淆吗?假设你的意思是“指向对象的内部指针的值”,“传递引用”和“传递引用的值”之间没有概念上的区别。 - izb
但是有一个微妙的区别。看看第一个例子。如果它纯粹是通过引用传递,aDog.name将是“Fifi”。它不是 - 你得到的参考是一个值引用,如果在退出函数时将被覆盖,将被恢复。 - erlando
@Lorenzo:不,在Java中,一切都是按价值传递的。基元按值传递,对象引用按值传递。对象本身永远不会传递给方法,但是对象总是在堆中,只有对象的引用传递给方法。 - Esko Luontola
我想要一种可视化对象传递的好方法:想象一下气球。调用fxn就像将第二个字符串绑定到气球并将该行传递给fxn。 parameter = new Balloon()将剪切该字符串并创建一个新的气球(但这对原始气球没有影响)。 parameter.pop()仍然会弹出它,因为它跟随字符串到同一个原始气球。 Java是按值传递的,但传递的值不是很深,而是处于最高级别,即基元或指针。不要将其与完全克隆和传递对象的深度传递混淆。 - dhackner
令人困惑的是,对象引用实际上是指针。在一开始,SUN称他们为指针。然后营销人员告知“指针”是一个坏词。但是你仍然可以在NullPointerException中看到“正确的”命名法。 - Prof. Falken


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

Java规范说Java中的所有内容都是按值传递的。在Java中没有“pass-by-reference”这样的东西。

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

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 (地址为42的那个)被要求将他的名字改为Max
  • 在线“BBB”
    • 一个新的 Dog 被建造。让我们说他在地址74
    • 我们分配参数 someDog 到74
  • 在线“CCC”
    • someDog跟着去了 Dog 它指向( Dog 地址对象74)
    • Dog (地址为74的那个)被要求将他的名字改为Rowlf
  • 然后,我们回来了

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

难道 myDog 更改?

关键是。

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

这完全有效 跟随 一个地址,并改变它的结尾;但是,这不会改变变量。

Java的工作方式与C完全相同。您可以分配指针,将指针传递给方法,按照方法中的指针操作并更改指向的数据。但是,您无法更改指针指向的位置。

在C ++,Ada,Pascal和其他支持pass-by-reference的语言中,您实际上可以更改传递的变量。

如果Java具有pass-by-reference语义,那么 foo 我们上面定义的方法会改变在哪里 myDog 在分配时指向 someDog 在线BBB。

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


2639



这就是为什么常见的副词“Java没有指针”是如此误导。 - Beska
你错了,imho。 “记住myDog是一个指针,而不是一个真正的狗,答案是否定的。我的狗仍然有42值;它仍然指向原来的狗。” myDog的值为42,但其名称参数现在包含“Max”,而不是// AAA行上的“Rover”。 - Özgür
这样想吧。有人在一张名为“annArborLocation”的纸条上写着密歇根州安娜堡(我的家乡,GO BLUE!)的地址。你把它复制在一张名为“myDestination”的纸上。你可以开车去“myDestination”并种一棵树。您可能在该位置更改了有关城市的信息,但它并未更改任何纸张上写入的LAT / LON。您可以在“myDestination”上更改LAT / LON,但不会更改“annArborLocation”。这有帮助吗? - Scott Stanchfield
@Scott Stanchfield:大约一年前我读过你的文章,这对我来说真的很有帮助。谢谢!我可以谦卑地建议一点补充:你应该提到的是,实际上有一个特定的术语描述了这种形式的“价值呼唤,其中价值是参考”,Barbara Liskov发明了这种形式,用于描述她的CLU语言的评估策略。 1974年,为了避免混淆,例如您的文章所述的内容: 通过分享来打电话 (有时称为 通过对象共享来调用 或简单地说 按对象调用),几乎完美地描述了语义。 - Jörg W Mittag
@Gevorg - C / C ++语言不具有“指针”的概念。还有其他语言使用指针但不允许C / C ++允许的相同类型的指针操作。 Java有指针;他们只是防止恶作剧。 - Scott Stanchfield


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

我将逐步解释这个:

  1. 声明一个名为的引用 f 类型 Foo 并将其分配给类型的新对象 Foo 有一个属性 "f"

    Foo f = new Foo("f");
    

    enter image description here

  2. 从方法方面来看,类型的引用 Foo 有一个名字 a 声明并且它最初被分配给 null

    public static void changeReference(Foo a)
    

    enter image description here

  3. 当你调用方法时 changeReference, 参考资料 a 将被分配给作为参数传递的对象。

    changeReference(f);
    

    enter image description here

  4. 声明一个名为的引用 b 类型 Foo 并将其分配给类型的新对象 Foo 有一个属性 "b"

    Foo b = new Foo("b");
    

    enter image description here

  5. a = b 正在重新分配参考 a 不 f 到其属性为的对象 "b"

    enter image description here


  6. 你打电话的时候 modifyReference(Foo c) 方法,参考 c 创建并使用属性分配给对象 "f"

    enter image description here

  7. c.setAttribute("c"); 将更改引用的对象的属性 c 指向它,它与引用的对象相同 f 指向它。

    enter image description here

我希望你现在明白如何将对象作为参数传递在Java中:)


1392



+1好东西。好的图表。我还在这里找到了一个简洁的页面 adp-gmbh.ch/php/pass_by_reference.html 好吧我承认它是用PHP编写的,但它是理解我认为重要的差异(以及如何根据您的需求操纵这种差异)的原则。 - DaveM
@ Eng.Fouad这是一个很好的解释,但如果 a 指向同一个对象 f (并且永远不会获得自己的对象副本 f 指向),使用的对象的任何更改 a 应该修改 f 还有(因为他们都在使用相同的对象),所以在某些时候 a 必须得到自己的 复制 对象 f 指着。 - Mr D
@MrD当'a'指向同一个对象'f'也指向时,那么通过'a'对该对象所做的任何改变也可以通过'f'观察到,但是它不会改变'f'。 'f'仍然指向同一个对象。你可以完全改变对象,但你永远不能改变'f'指向的对象。这是一些基本问题,由于某些原因,有些人无法理解。 - Mike Braun
这是我发现的最佳解释。顺便问一下,基本情况怎么样?例如,参数需要一个int类型,它是否仍然将int变量的副本传递给参数? - allenwang
图表非常有用 - Ivan Kaloyanov


这将为您提供有关Java如何工作的一些见解,以至于在您下次讨论Java通过引用传递或通过值传递时,您只需微笑:-)

第一步请从脑海中删除以'p'“_ _ _ _ _ _ _”开头的单词,特别是如果您来自其他编程语言。 Java和'p'不能写在同一本书,论坛甚至txt中。

第二步记住,当你将一个Object传递给一个方法时,你传递的是Object引用,而不是Object本身。

  • 学生:Master,这是否意味着Java是通过引用传递的?
  • :蚱蜢,没有。

现在想想Object的引用/变量是什么/是什么:

  1. 变量保存位,告诉JVM如何到达内存中引用的Object(Heap)。
  2. 将参数传递给方法时 您没有传递引用变量,而是传递引用变量中的位副本。像这样:3bad086a。 3bad086a表示获取传递对象的方法。
  3. 所以你只是传递3bad086a它是引用的值。
  4. 您传递的是引用的值而不是引用本身(而不是对象)。
  5. 该值实际上是COPIED并赋予方法

在下面(请不要尝试编译/执行此...):

1. Person person;
2. person = new Person("Tom");
3. changeName(person);
4.
5. //I didn't use Person person below as an argument to be nice
6. static void changeName(Person anotherReferenceToTheSamePersonObject) {
7.     anotherReferenceToTheSamePersonObject.setName("Jerry");
8. }

怎么了?

  • 变量  在第1行创建,它在开头是null。
  • 在第2行创建一个新的Person对象,存储在内存中,以及变量  给出了Person对象的引用。那就是它的地址。比方说3bad086a。
  • 变量  保持Object的地址传递给第3行的函数。
  • 在第4行,你可以听到沉默的声音
  • 检查第5行的评论
  • 方法局部变量 - anotherReferenceToTheSamePersonObject - 创建然后来到第6行的魔力:
    • 变量/引用  被逐位复制并传递给 anotherReferenceToTheSamePersonObject 在功能里面。
    • 没有创建Person的新实例。
    • 两个““和”anotherReferenceToTheSamePersonObject“保持相同的3bad086a值。
    • 不要试试这个,但是人== anotherReferenceToTheSamePersonObject会是真的。
    • 两个变量都具有引用的IDENTICAL COPIES,它们都引用相同的Person对象,堆上的SAME对象而不是COPY。

一张图片胜过千言万语:

Pass by Value

请注意,anotherReferenceToTheSamePersonObject箭头指向Object而不是指向变量person!

如果你没有得到它,那么请相信我,并记住最好这么说 Java是按值传递的。好, 通过参考值传递。哦,更好的是 传址复制的最值变量的值! ;)

现在随时恨我,但请注意这一点 传递原始数据类型和对象之间没有区别 在谈论方法论证时。

您总是传递参考值的位副本!

  • 如果它是原始数据类型,则这些位将包含原始数据类型本身的值。
  • 如果它是一个Object,那么这些位将包含告诉JVM如何到达Object的地址值。

Java是按值传递的,因为在方法中你可以根据需要修改引用的对象,但无论你怎么努力,你都永远无法修改将继续引用的传递变量(不是p _ _ _ _ _ _ _)同样的对象无论如何!


上面的changeName函数永远不能修改传递的引用的实际内容(位值)。换句话说,changeName不能使Person人引用另一个Object。


当然你可以缩短它,然后说出来 Java是按值传递的!


651



你的意思是指针吗?如果我得到正确的话,在 public void foo(Car car){ ... }, car 是当地的 foo 它包含Object的堆位置?所以,如果我改变 car的价值 car = new Car(),它会指向堆上的不同Object吗?如果我改变了 car的财产价值由 car.Color = "Red",堆中的Object指向的 car 将被修改。另外,它在C#中是一样的吗?请回复!谢谢! - dpp
@domanokz你杀了我,请不要再说这个词了! ;)请注意,我可以回答这个问题而不说“引用”。这是一个术语问题,并且'使情况变得更糟。不幸的是,我和苏格兰人对此有不同的看法。我认为你已经掌握了它在Java中的工作原理,现在你可以将它称为按值传递,按对象共享,按副本复制变量值,或者随意提出其他内容!只要你知道它的工作方式以及Object类型的变量中的内容,我就不在乎了!只是一个邮政信箱地址! ;) - Gevorg
听起来像你一样 通过了参考?我将支持Java仍然是一种复制的传递引用语言这一事实​​。它是复制引用的事实不会改变术语。两个REFERENCES仍然指向同一个对象。这是纯粹主义者的论点...... - John Strickler
我想Java设计时考虑了指针。否则,为什么 NullPointerException 存在?然而,对于这个精彩的解释,获取指针只会让它变得复杂 - brain storm
因此,请参阅理论上的第9行 System.out.println(person.getName()); 什么会出现? “汤姆”还是“杰瑞”?这是帮助我克服这种混乱的最后一件事。 - TheBrenny


Java总是按值传递,没有例外, 曾经

那么如何让任何人都对此感到困惑,并相信Java是通过引用传递的,或者认为他们有一个Java作为传递参考的例子?关键是Java 决不 提供对价值的直接访问 对象本身,在 任何 情况。对象的唯一访问是通过a 参考 到那个对象。因为Java对象是 总是 通过引用访问,而不是直接访问,通常谈论字段和变量 和方法参数 作为 对象,当他们只是迂腐 对象的引用这种混淆源于这种(严格来说,不正确的)命名法的变化。

所以,在调用方法时

  • 对于原始论点(intlong,等等,通过值是 实际价值 原语(例如,3)。
  • 对于对象,pass by value是值 对象的引用

所以,如果你有 doSomething(foo) 和 public void doSomething(Foo foo) { .. } 这两个Foos已经复制了 引用 指向相同的对象。

当然,通过值传递对对象的引用看起来非常像(并且在实践中无法区分)通过引用传递对象。


561



由于基元的值是不可变的(如String),因此两种情况之间的差异并不重要。 - Paŭlo Ebermann
究竟。对于所有你可以通过可观察的JVM行为来判断,原语可以通过引用传递,并且可以存在于堆上。他们没有,但实际上并没有以任何方式观察到。 - Gravity
原语是不可改变的?是Java 7中的新功能吗? - Carlos Heuberger
@CarlosHeuberger,“原始人是不变的?”。关键是你可以 假装 那些'原始'实际上是(可变的) 引用 到不可变对象。 - Aaron McDaid
指针是不可变的,原始一般是可变的。 String也不是原始的,它是一个对象。而且,String的底层结构是一个可变数组。关于它的唯一不可变的事情是长度,这是数组的固有特性。 - kingfrito_5005


Java按值传递引用。

因此,您无法更改传入的引用。


279



但是不断重复的事情“你无法改变在参数中传递的对象的值”显然是错误的。您可能无法使它们引用其他对象,但您可以通过调用其方法来更改其内容。 IMO这意味着您将失去参考的所有好处,并且不会获得额外的保证。 - Timmmm
我从来没有说过“你不能改变在参数中传递的对象的价值”。我会说“你不能改变作为方法参数传入的对象引用的值”,这是关于Java语言的真实陈述。显然你可以改变对象的状态(只要它不是不可变的)。 - ScArcher2
请记住,您实际上无法在java中传递对象;对象留在堆上。 指针 可以传递对象(将其复制到被调用方法的堆栈帧中)。因此,您永远不会更改传入的值(指针),但您可以自由地关注它并更改它所指向的堆上的内容。这是价值传递。 - Scott Stanchfield
听起来像你一样 通过了参考?我将支持Java仍然是一种复制的传递引用语言这一事实​​。它是复制引用的事实不会改变术语。两个REFERENCES仍然指向同一个对象。这是纯粹主义者的论点...... - John Strickler
Java不传递对象,它将指针的值传递给对象。这将在新变量中创建一个指向原始对象的内存位置的新指针。如果在方法中更改此指针变量的值(它指向的内存地址),则方法调用方中使用的原始指针保持不变。如果你正在调用参数一个引用,那么事实就是它 复制 原始引用,而不是原始引用本身,以便现在有两个对象的引用意味着它是按值传递 - theferrit32


我觉得争论“传递引用与传递价值”并不是非常有用。

如果你说“Java是任意的(参考/值)”,在任何一种情况下,你都没有提供完整的答案。这里有一些额外的信息,有助于理解记忆中发生的事情。

在我们进入Java实现之前,堆栈/堆上的崩溃过程: 价值观以有序的方式在堆栈中上下移动,就像在自助餐厅的一堆盘子一样。 堆中的内存(也称为动态内存)是杂乱无章的。 JVM只是在任何地方找到空间,并释放它,因为不再需要使用它的变量。

好的。首先,本地原语进入堆栈。所以这段代码:

int x = 3;
float y = 101.1f;
boolean amIAwesome = true;

结果如下:

primitives on the stack

声明和实例化对象时。实际的对象在堆上。什么在堆栈上?堆上对象的地址。 C ++程序员会将此称为指针,但是一些Java开发人员反对“指针”这个词。随你。只要知道对象的地址就在堆栈上。

像这样:

int problems = 99;
String name = "Jay-Z";

a b*7ch aint one!

数组是一个对象,所以它也在堆上。那阵列中的对象怎么样?它们获得自己的堆空间,每个对象的地址都在数组内部。

JButton[] marxBros = new JButton[3];
marxBros[0] = new JButton("Groucho");
marxBros[1] = new JButton("Zeppo");
marxBros[2] = new JButton("Harpo");

marx brothers

那么,当你调用一个方法时会传入什么?如果传入一个对象,那么实际传入的是对象的地址。有些人可能会说地址的“价值”,有些人说它只是对象的引用。这是“参考”和“价值”支持者之间圣战的起源。你所说的并不像你理解的那样重要,传入的是对象的地址。

private static void shout(String name){
    System.out.println("There goes " + name + "!");
}

public static void main(String[] args){
    String hisName = "John J. Jingleheimerschmitz";
    String myName = hisName;
    shout(myName);
}

创建一个String,并在堆中分配空间,并将字符串的地址存储在堆栈中并给出标识符 hisName,由于第二个String的地址与第一个String的地址相同,因此不会创建新的String并且不会分配新的堆空间,但会在堆栈上创建新的标识符。然后我们打电话 shout():创建一个新的堆栈框架和一个新的标识符, name 创建并分配已存在的String的地址。

la da di da da da da

那么,价值,参考?你说“土豆”。


198



但是,您应该跟进一个更复杂的示例,其中函数似乎将变量更改为其具有引用的地址。 - Brian Peterson
人们不是“围绕堆栈与堆积的真正问题跳舞”,因为那是 不 真正的问题。它充其量只是一个实现细节,而在最坏的情况下是彻头彻尾的错误。 (对象很可能存在于堆栈中;谷歌“逃避分析”。并且大量对象包含可能的基元 别 住在堆栈上。)真正的问题是 究竟 引用类型和值类型之间的区别 - 特别是,引用类型变量的值是引用,而不是它引用的对象。 - cHao
这是一个“实现细节”,因为Java永远不需要实际显示对象在内存中的位置,事实上似乎决心 避免 泄露这些信息。它可以把对象放在堆栈上,你永远不会知道。如果你关心,你就会专注于错误的事情 - 在这种情况下,这意味着忽略了真正的问题。 - cHao
无论哪种方式,“原始进入堆栈”都是不正确的。原始 局部变量 去堆栈。 (当然,如果它们没有被优化掉。)但是, 本地参考变量也是如此。在对象中定义的原始成员生活在对象所在的任何地方。 - cHao
同意这里的评论。堆栈/堆是一个侧面问题,并不相关。一些变量可能在堆栈上,一些变量在静态内存中(静态变量),并且堆上有很多变量(所有对象成员变量)。这些变量中的任何一个都不能通过引用传递:从被调用的方法中,永远不可能更改作为参数传递的变量的值。因此,Java中没有pass-by-reference。 - fishinear


只是为了显示对比,请比较以下内容 C ++ 和 Java的 片段:

在C ++中: 注意:代码错误 - 内存泄漏!  但它证明了这一点。

void cppMethod(int val, int &ref, Dog obj, Dog &objRef, Dog *objPtr, Dog *&objPtrRef)
{
    val = 7; // Modifies the copy
    ref = 7; // Modifies the original variable
    obj.SetName("obj"); // Modifies the copy of Dog passed
    objRef.SetName("objRef"); // Modifies the original Dog passed
    objPtr->SetName("objPtr"); // Modifies the original Dog pointed to 
                               // by the copy of the pointer passed.
    objPtr = new Dog("newObjPtr");  // Modifies the copy of the pointer, 
                                   // leaving the original object alone.
    objPtrRef->SetName("objRefPtr"); // Modifies the original Dog pointed to 
                                    // by the original pointer passed. 
    objPtrRef = new Dog("newObjPtrRef"); // Modifies the original pointer passed
}

int main()
{
    int a = 0;
    int b = 0;
    Dog d0 = Dog("d0");
    Dog d1 = Dog("d1");
    Dog *d2 = new Dog("d2");
    Dog *d3 = new Dog("d3");
    cppMethod(a, b, d0, d1, d2, d3);
    // a is still set to 0
    // b is now set to 7
    // d0 still have name "d0"
    // d1 now has name "objRef"
    // d2 now has name "objPtr"
    // d3 now has name "newObjPtrRef"
}

在Java中

public static void javaMethod(int val, Dog objPtr)
{
   val = 7; // Modifies the copy
   objPtr.SetName("objPtr") // Modifies the original Dog pointed to 
                            // by the copy of the pointer passed.
   objPtr = new Dog("newObjPtr");  // Modifies the copy of the pointer, 
                                  // leaving the original object alone.
}

public static void main()
{
    int a = 0;
    Dog d0 = new Dog("d0");
    javaMethod(a, d0);
    // a is still set to 0
    // d0 now has name "objPtr"
}

Java只有两种类型的传递:内置类型的值,以及对象类型的指针值。


161



+1我也会补充 Dog **objPtrPtr 对于C ++示例,我们可以通过这种方式修改指针“指向”的内容。 - Amro
这是迄今为止我见过的最好的答案之一。它主要避免了其他地方出现的“参考与参考值”的无关语义论证,而是讨论了实际发生的机制。由于他们的自相矛盾或事实错误的内容,我不得不给出大多数其他“按值传递”的答案-1,但这个答案会得+1。 - Aaron


Java按值传递对象的引用。


145



就如此容易 ! - Ivan Kaloyanov