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" 。 在函数foo中,函数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); 

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

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

myDog改变了吗?

有关键。

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

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

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

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

如果Java具有引用传递语义,那么我们上面定义的foo方法将在myDog所指向的位置发生改变,因为它在BBB行上分配了一些someDog

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

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. 声明一个名为fFootypes的引用,并将其赋值给一个具有属性"f" Footypes的新对象。

     Foo f = new Foo("f"); 

    在这里输入图像描述

  2. 从方法的angular度来说,名为a Footypes的引用被声明,并且最初被赋值为null

     public static void changeReference(Foo a) 

    在这里输入图像描述

  3. 在调用方法changeReference ,引用a将被分配给作为parameter passing的对象。

     changeReference(f); 

    在这里输入图像描述

  4. 声明一个名为bFootypes的引用,并将其赋值给一个具有属性"b" Footypes的新对象。

     Foo b = new Foo("b"); 

    在这里输入图像描述

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

    在这里输入图像描述


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

    在这里输入图像描述

  7. c.setAttribute("c"); 会改变引用c点的对象的属性,而引用f指向它的是同一个对象。

    在这里输入图像描述

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

这会给你一些关于Java如何真正起作用的见解,在下一个关于Java通过引用传递或通过值传递的讨论中,你只会微笑:-)

第一步请从头脑中清除以'p'开头的词,尤其是如果你来自其他编程语言。 Java和'p'不能写在同一本书,论坛甚至txt中。

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

  • 学生 :师父,这是否意味着Java是通过引用?
  • 师父 :蚱蜢

现在想想对象的引用/variables是做什么的:

  1. 一个variables保存指示JVM如何到达内存中引用对象(Heap)的位。
  2. 将parameter passing给方法时, 您不会传递引用variables,而是引用variables中的位的副本 。 像这样的: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. } 

怎么了?

  • variablesperson在行#1中创build,并在开始时为空。
  • 在#2行创build一个新的Person对象,存储在内存中,variablesPerson被赋予对Person对象的引用。 就是它的地址。 比方说3bad086a。
  • 保存Object的地址的variables人员被传递给第3行的函数。
  • 在#4线你可以听到沉默的声音
  • 检查第5行的注释
  • 一个方法局部variables – anotherReferenceToTheSamePersonObject – 被创build,然后在#6行来:
    • variables/引用被逐位复制并传递给函数内的另一个参考对象。
    • 没有创buildPerson的新实例。
    • person ”和“ anotherReferenceToTheSamePersonObject ”都保持3bad086a的相同值。
    • 不要尝试这个,但人== anotherReferenceToTheSamePersonObject将是真实的。
    • 两个variables都有引用的IDENTICAL COPIES,它们都引用同一个Person对象,堆上的SAME对象,而不是COPY。

一张图片胜过千言万语:

通过价值

请注意anotherReferenceToTheSamePersonObject箭头是针​​对对象,而不是对variables的人!

如果你没有得到它,那么只要相信我,记住最好说Java是通过价值传递的 。 那么, 通过参考值 。 哦,更好的是传递可变值的副本! ;)

现在可以自由地讨厌我,但是请注意,在讨论方法参数时,传递原始数据types和对象之间没有区别

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

  • 如果是基本数据types,这些位将包含基本数据types本身的值。
  • 如果它是一个对象,这些位将包含告诉JVM如何到达对象的地址的值。

Java是通过值传递的,因为在一个方法中,你可以尽可能多地修改被引用的对象,但是不pipe你怎么努力,你永远不能修改传入的variables来保持引用(而不是p _ _ _ _ _ _ _)相同的对象无论如何!


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


当然,你可以缩短它,只是说Java是通过值!

Java永远是值得传递的,没有例外。

那么为什么任何人都可以被这个混淆,相信Java是通过引用,或者认为他们有一个Java作为通过引用的例子? 关键是在任何情况下,Java都不会直接访问对象本身的值。 唯一访问对象是通过对该对象的引用 。 由于Java对象总是通过引用访问,而不是直接访问,所以通常将字段,variables和方法参数作为对象进行讨论 ,因为它们只是对象的引用混淆源于这个(严格来说是错误的)命名的变化。

所以,当调用一个方法

  • 对于原始参数( intlong等),按值传递是基元的实际值 (例如3)。
  • 对于对象,按值传递是对对象引用的值。

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

自然地,通过值传递一个对象的引用看起来非常像(在实践中难以区分)通过引用传递一个对象。

Java按值传递引用。

所以你不能改变传入的引用。

为了显示对比,请比较以下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只有两种types的传递:通过内置types的值和对象types的指针的值。

我觉得自己争论的是“引用传递与价值传递”不是超级有用的。

如果你说,“Java是通过任何(参考/价值)”,但无论如何你没有提供一个完整的答案。 这里有一些额外的信息将有助于理解内存中发生的事情。

在我们开始Java实现之前,堆栈/堆的崩溃过程:值以一种非常有序的方式上下堆叠,就像自助餐厅里的一堆盘子一样。 堆中的记忆(也称为dynamic记忆)是杂乱无章的。 JVM只需find空间,然后将其释放,因为不再需要使用它的variables。

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

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

结果如下:

原语在堆栈上

当你声明和实例化一个对象。 实际的物体堆积如山。 什么是堆栈? 堆上的对象的地址。 C ++程序员会把这个叫做指针,但是一些Java开发者对“指针”这个词是种族歧视。 随你。 只要知道对象的地址在堆栈中。

像这样:

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

a b * 7ch aint one!

一个数组是一个对象,所以它也在堆上。 那么arrays中的物体呢? 他们得到自己的堆空间,每个对象的地址都在数组内。

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

马克思兄弟

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

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

创build一个string并在堆中分配空间,并将string的地址存储在堆栈上,并给定标识符hisName ,因为第二个string的地址与第一个string的地址相同,所以不会创build新的string并没有分配新的堆空间,但在堆栈上创build了一个新的标识符。 然后我们调用shout() :创build一个新的堆栈框架,并创build一个新的标识符name ,并分配已经存在的String的地址。

拉达迪达达达

那么,价值,参考? 你说“马铃薯”。

Java通过值传递对象的引用。

我不敢相信没有人提到Barbara Liskov。 当她在1974年deviseCLU时,她遇到了同样的术语问题,她发明了这个术语“ 通过分享呼叫” (也就是对象共享对象呼叫 )一个参考“。

Basically, reassigning Object parameters doesn't affect the argument, eg,

 private void foo(Object bar) { bar = null; } public static void main(String[] args) { String baz = "Hah!"; foo(baz); System.out.println(baz); } 

will print out "Hah!" instead of NULL . The reason this works is because bar is a copy of the value of baz , which is just a reference to "Hah!" 。 If it were the actual reference itself, then foo would have redefined baz to null .

The crux of the matter is that the word reference in the expression "pass by reference" means something completely different from the usual mening of the word reference in Java.

Usually in Java reference means aa reference to an object . But the technical terms pass by reference/value from programming language theory is talking about a reference to the memory cell holding the variable , which is someting completely different.

In java everything is reference, so when you have something like: Point pnt1 = new Point(0,0); Java does following:

  1. Creates new Point object
  2. Creates new Point reference and initialize that reference to point (refer to) on previously created Point object.
  3. From here, through Point object life, you will access to that object through pnt1 reference. So we can say that in Java you manipulate object through its reference.

在这里输入图像描述

Java doesn't pass method arguments by reference; it passes them by value. I will use example from this site :

 public static void tricky(Point arg1, Point arg2) { arg1.x = 100; arg1.y = 100; Point temp = arg1; arg1 = arg2; arg2 = temp; } public static void main(String [] args) { Point pnt1 = new Point(0,0); Point pnt2 = new Point(0,0); System.out.println("X1: " + pnt1.x + " Y1: " +pnt1.y); System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y); System.out.println(" "); tricky(pnt1,pnt2); System.out.println("X1: " + pnt1.x + " Y1:" + pnt1.y); System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y); } 

Flow of the program:

 Point pnt1 = new Point(0,0); Point pnt2 = new Point(0,0); 

Creating two different Point object with two different reference associated. 在这里输入图像描述

 System.out.println("X1: " + pnt1.x + " Y1: " +pnt1.y); System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y); System.out.println(" "); 

As expected output will be:

 X1: 0 Y1: 0 X2: 0 Y2: 0 

On this line 'pass-by-value' goes into the play…

 tricky(pnt1,pnt2); public void tricky(Point arg1, Point arg2); 

References pnt1 and pnt2 are passed by value to the tricky method, which means that now yours references pnt1 and pnt2 have their copies named arg1 and arg2 .So pnt1 and arg1 points to the same object. (Same for the pnt2 and arg2 ) 在这里输入图像描述

In the tricky method:

  arg1.x = 100; arg1.y = 100; 

在这里输入图像描述

Next in the tricky method

 Point temp = arg1; arg1 = arg2; arg2 = temp; 

Here, you first create new temp Point reference which will point on same place like arg1 reference. Then you move reference arg1 to point to the same place like arg2 reference. Finally arg2 will point to the same place like temp .

在这里输入图像描述

From here scope of tricky method is gone and you don't have access any more to the references: arg1 , arg2 , temp . But important note is that everything you do with these references when they are 'in life' will permanently affect object on which they are point to.

So after executing method tricky , when you return to main , you have this situation: 在这里输入图像描述

So now, completely execution of program will be:

 X1: 0 Y1: 0 X2: 0 Y2: 0 X1: 100 Y1: 100 X2: 0 Y2: 0 

A reference is always a value when represented, no matter what language you use.

Getting an outside of the box view, let's look at Assembly or some low level memory management. At the CPU level a reference to anything immediately becomes a value if it gets written to memory or to one of the CPU registers. (That is why pointer is a good definition. It is a value, which has a purpose at the same time).

Data in memory has a Location and at that location there is a value (byte,word, whatever). In Assembly we have a convenient solution to give a Name to certain Location (aka variable), but when compiling the code, the assembler simply replaces Name with the designated location just like your browser replaces domain names with IP addresses.

Down to the core it is technically impossible to pass a reference to anything in any language without representing it (when it immediately becomes a value).

Lets say we have a variable Foo, its Location is at the 47th byte in memory and its Value is 5. We have another variable Ref2Foo which is at 223rd byte in memory, and its value will be 47. This Ref2Foo might be a technical variable, not explicitly created by the program. If you just look at 5 and 47 without any other information, you will see just two Values . If you use them as references then to reach to 5 we have to travel:

 (Name)[Location] -> [Value at the Location] --------------------- (Ref2Foo)[223] -> 47 (Foo)[47] -> 5 

This is how jump-tables work.

If we want to call a method/function/procedure with Foo's value, there are a few possible way to pass the variable to the method, depending on the language and its several method invocation modes:

  1. 5 gets copied to one of the CPU registers (ie. EAX).
  2. 5 gets PUSHd to the stack.
  3. 47 gets copied to one of the CPU registers
  4. 47 PUSHd to the stack.
  5. 223 gets copied to one of the CPU registers.
  6. 223 gets PUSHd to the stack.

In every cases above a value – a copy of an existing value – has been created, it is now upto the receiving method to handle it. When you write "Foo" inside the method, it is either read out from EAX, or automatically dereferenced , or double dereferenced, the process depends on how the language works and/or what the type of Foo dictates. This is hidden from the developer until she circumvents the dereferencing process. So a reference is a value when represented, because a reference is a value that has to be processed (at language level).

Now we have passed Foo to the method:

  • in case 1. and 2. if you change Foo ( Foo = 9 ) it only affects local scope as you have a copy of the Value. From inside the method we cannot even determine where in memory the original Foo was located.
  • in case 3. and 4. if you use default language constructs and change Foo ( Foo = 11 ), it could change Foo globally (depends on the language, ie. Java or like Pascal's procedure findMin(x, y, z: integer; var m : integer); ). However if the language allows you to circumvent the dereference process, you can change 47 , say to 49 . At that point Foo seems to have been changed if you read it, because you have changed the local pointer to it. And if you were to modify this Foo inside the method ( Foo = 12 ) you will probably FUBAR the execution of the program (aka. segfault) because you will write to a different memory than expected, you can even modify an area that is destined to hold executable program and writing to it will modify running code (Foo is now not at 47 ). BUT Foo's value of 47 did not change globally, only the one inside the method, because 47 was also a copy to the method.
  • in case 5. and 6. if you modify 223 inside the method it creates the same mayhem as in 3. or 4. (a pointer, pointing to a now bad value, that is again used as a pointer) but this is still a local problem, as 223 was copied . However if you are able to dereference Ref2Foo (that is 223 ), reach to and modify the pointed value 47 , say, to 49 , it will affect Foo globally , because in this case the methods got a copy of 223 but the referenced 47 exists only once, and changing that to 49 will lead every Ref2Foo double-dereferencing to a wrong value.

Nitpicking on insignificant details, even languages that do pass-by-reference will pass values to functions, but those functions know that they have to use it for dereferencing purposes. This pass-the-reference-as-value is just hidden from the programmer because it is practically useless and the terminology is only pass-by-reference .

Strict pass-by-value is also useless, it would mean that a 100 Mbyte array should have to be copied every time we call a method with the array as argument, therefore Java cannot be stricly pass-by-value. Every language would pass a reference to this huge array (as a value) and either employs copy-on-write mechanism if that array can be changed locally inside the method or allows the method (as Java does) to modify the array globally (from the caller's view) and a few languages allows to modify the Value of the reference itself.

So in short and in Java's own terminology, Java is pass-by-value where value can be: either a real value or a value that is a representation of a reference .

No, it's not pass by reference.

Java is pass by value according to the Java Language Specification:

When the method or constructor is invoked (§15.12), the values of the actual argument expressions initialize newly created parameter variables , each of the declared type, before execution of the body of the method or constructor. The Identifier that appears in the DeclaratorId may be used as a simple name in the body of the method or constructor to refer to the formal parameter .

As far as I know, Java only knows call by value. This means for primitive datatypes you will work with an copy and for objects you will work with an copy of the reference to the objects. However I think there are some pitfalls; for example, this will not work:

 public static void swap(StringBuffer s1, StringBuffer s2) { StringBuffer temp = s1; s1 = s2; s2 = temp; } public static void main(String[] args) { StringBuffer s1 = new StringBuffer("Hello"); StringBuffer s2 = new StringBuffer("World"); swap(s1, s2); System.out.println(s1); System.out.println(s2); } 

This will populate Hello World and not World Hello because in the swap function you use copys which have no impact on the references in the main. But if your objects are not immutable you can change it for example:

 public static void appendWorld(StringBuffer s1) { s1.append(" World"); } public static void main(String[] args) { StringBuffer s = new StringBuffer("Hello"); appendWorld(s); System.out.println(s); } 

This will populate Hello World on the command line. If you change StringBuffer into String it will produce just Hello because String is immutable. 例如:

 public static void appendWorld(String s){ s = s+" World"; } public static void main(String[] args) { String s = new String("Hello"); appendWorld(s); System.out.println(s); } 

However you could make a wrapper for String like this which would make it able to use it with Strings:

 class StringWrapper { public String value; public StringWrapper(String value) { this.value = value; } } public static void appendWorld(StringWrapper s){ s.value = s.value +" World"; } public static void main(String[] args) { StringWrapper s = new StringWrapper("Hello"); appendWorld(s); System.out.println(s.value); } 

edit: i believe this is also the reason to use StringBuffer when it comes to "adding" two Strings because you can modifie the original object which u can't with immutable objects like String is.

Let me try to explain my understanding with the help of four examples. Java is pass-by-value, and not pass-by-reference

/ **

Pass By Value

In Java, all parameters are passed by value, ie assigning a method argument is not visible to the caller.

* /

Example 1:

 public class PassByValueString { public static void main(String[] args) { new PassByValueString().caller(); } public void caller() { String value = "Nikhil"; boolean valueflag = false; String output = method(value, valueflag); /* * 'output' is insignificant in this example. we are more interested in * 'value' and 'valueflag' */ System.out.println("output : " + output); System.out.println("value : " + value); System.out.println("valueflag : " + valueflag); } public String method(String value, boolean valueflag) { value = "Anand"; valueflag = true; return "output"; } } 

结果

 output : output value : Nikhil valueflag : false 

Example 2:

/** * * Pass By Value * */

 public class PassByValueNewString { public static void main(String[] args) { new PassByValueNewString().caller(); } public void caller() { String value = new String("Nikhil"); boolean valueflag = false; String output = method(value, valueflag); /* * 'output' is insignificant in this example. we are more interested in * 'value' and 'valueflag' */ System.out.println("output : " + output); System.out.println("value : " + value); System.out.println("valueflag : " + valueflag); } public String method(String value, boolean valueflag) { value = "Anand"; valueflag = true; return "output"; } } 

结果

 output : output value : Nikhil valueflag : false 

Example 3:

/** This 'Pass By Value has a feeling of 'Pass By Reference'

Some people say primitive types and 'String' are 'pass by value' and objects are 'pass by reference'.

But from this example, we can understand that it is infact pass by value only, keeping in mind that here we are passing the reference as the value. ie: reference is passed by value. That's why are able to change and still it holds true after the local scope. But we cannot change the actual reference outside the original scope. what that means is demonstrated by next example of PassByValueObjectCase2.

* /

 public class PassByValueObjectCase1 { private class Student { int id; String name; public Student() { } public Student(int id, String name) { super(); this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + "]"; } } public static void main(String[] args) { new PassByValueObjectCase1().caller(); } public void caller() { Student student = new Student(10, "Nikhil"); String output = method(student); /* * 'output' is insignificant in this example. we are more interested in * 'student' */ System.out.println("output : " + output); System.out.println("student : " + student); } public String method(Student student) { student.setName("Anand"); return "output"; } } 

结果

 output : output student : Student [id=10, name=Anand] 

Example 4:

/ **

In addition to what was mentioned in Example3 (PassByValueObjectCase1.java), we cannot change the actual reference outside the original scope."

Note: I am not pasting the code for private class Student . The class definition for Student is same as Example3.

* /

 public class PassByValueObjectCase2 { public static void main(String[] args) { new PassByValueObjectCase2().caller(); } public void caller() { // student has the actual reference to a Student object created // can we change this actual reference outside the local scope? Let's see Student student = new Student(10, "Nikhil"); String output = method(student); /* * 'output' is insignificant in this example. we are more interested in * 'student' */ System.out.println("output : " + output); System.out.println("student : " + student); // Will it print Nikhil or Anand? } public String method(Student student) { student = new Student(20, "Anand"); return "output"; } } 

结果

 output : output student : Student [id=10, name=Nikhil] 

You can never pass by reference in Java, and one of the ways that is obvious is when you want to return more than one value from a method call. Consider the following bit of code in C++:

 void getValues(int& arg1, int& arg2) { arg1 = 1; arg2 = 2; } void caller() { int x; int y; getValues(x, y); cout << "Result: " << x << " " << y << endl; } 

Sometimes you want to use the same pattern in Java, but you can't; at least not directly. Instead you could do something like this:

 void getValues(int[] arg1, int[] arg2) { arg1[0] = 1; arg2[0] = 2; } void caller() { int[] x = new int[1]; int[] y = new int[1]; getValues(x, y); System.out.println("Result: " + x[0] + " " + y[0]); } 

As was explained in previous answers, in Java you're passing a pointer to the array as a value into getValues . That is enough, because the method then modifies the array element, and by convention you're expecting element 0 to contain the return value. Obviously you can do this in other ways, such as structuring your code so this isn't necessary, or constructing a class that can contain the return value or allow it to be set. But the simple pattern available to you in C++ above is not available in Java.

I thought I'd contribute this answer to add more details from the Specifications.

First, What's the difference between passing by reference vs. passing by value?

Passing by reference means the called functions' parameter will be the same as the callers' passed argument (not the value, but the identity – the variable itself).

Pass by value means the called functions' parameter will be a copy of the callers' passed argument.

Or from wikipedia, on the subject of pass-by-reference

In call-by-reference evaluation (also referred to as pass-by-reference), a function receives an implicit reference to a variable used as argument, rather than a copy of its value. This typically means that the function can modify (ie assign to) the variable used as argument—something that will be seen by its caller.

And on the subject of pass-by-value

In call-by-value, the argument expression is evaluated, and the resulting value is bound to the corresponding variable in the function […]. If the function or procedure is able to assign values to its parameters, only its local copy is assigned […].

Second, we need to know what Java uses in its method invocations. The Java Language Specification states

When the method or constructor is invoked (§15.12), the values of the actual argument expressions initialize newly created parameter variables , each of the declared type, before execution of the body of the method or constructor.

So it assigns (or binds) the value of the argument to the corresponding parameter variable.

What is the value of the argument?

Let's consider reference types, the Java Virtual Machine Specification states

There are three kinds of reference types : class types, array types, and interface types. Their values are references to dynamically created class instances, arrays, or class instances or arrays that implement interfaces, respectively.

The Java Language Specification also states

The reference values (often just references) are pointers to these objects , and a special null reference, which refers to no object.

The value of an argument (of some reference type) is a pointer to an object. Note that a variable, an invocation of a method with a reference type return type, and an instance creation expression ( new ... ) all resolve to a reference type value.

所以

 public void method (String param) {} ... String var = new String("ref"); method(var); method(var.toString()); method(new String("ref")); 

all bind the value of a reference to a String instance to the method's newly created parameter, param . This is exactly what the definition of pass-by-value describes. As such, Java is pass-by-value .

The fact that you can follow the reference to invoke a method or access a field of the referenced object is completely irrelevant to the conversation. The definition of pass-by-reference was

This typically means that the function can modify (ie assign to) the variable used as argument—something that will be seen by its caller.

In Java, modifying the variable means reassigning it. In Java, if you reassigned the variable within the method, it would go unnoticed to the caller. Modifying the object referenced by the variable is a different concept entirely.


Primitive values are also defined in the Java Virtual Machine Specification, here . The value of the type is the corresponding integral or floating point value, encoded appropriately (8, 16, 32, 64, etc. bits).

The distinction, or perhaps just the way I remember as I used to be under the same impression as the original poster is this: Java is always pass by value. All objects( in Java, anything except for primitives) in Java are references. These references are passed by value.

Java is always pass by values NOT pass by reference

first of we understand what is pass by value and pass by reference

pass by value means you are making a copy in memory of the actual parameter's value that is passed in, a copy of the contents of the actual parameter

pass by reference (also called pass by address), a copy of the address of the actual parameter is stored

Some time it gives illusion pass by reference.lets see how it works by example

 public class Passbyvalue { public static void main(String[] args) { test t=new test(); t.name="initialvalue"; new Passbyvalue().changeValue(t); System.out.println(t.name); } public void changeValue(test f){ f.name="changevalue"; } } class test{ String name; } 

Output of this program is

changevalue

lets understand step by step

test t=new test();

as we all know it will create object in heap and return return reference value back to t. suppose for example value of t is 0x100234(its JVM internal value as we don't about it i have just consider it for example)

在这里输入图像描述

new Passbyvalue().changeValue(t);

when passing reference t to function it will not directly pass actual reference value of object test but it will create copy of t and then it pass to function ( as it pass by value it passes copy of variable not actual reference of it) . As we consider value of t will be0x100234 . so in this way both t and f will have same value and hence they will point to same object

在这里输入图像描述

so if you change any thing in function using reference f it will modify existing contain of object that why we were getting output "changevalue" which is updated in function

to understand this more clearly consider following example

 public class Passbyvalue { public static void main(String[] args) { test t=new test(); t.name="initialvalue"; new Passbyvalue().changerefence(t); System.out.println(t.name); } public void changerefence(test f){ f=null; } } class test{ String name; } 

will it give null pointer no because it passes only copy of reference .In case of by reference it could have given nullpointer exception

在这里输入图像描述

Hopefully this will help

Java is a call by value.

How it works.

  • You always pass a copy of the bits of the value of the reference!

  • If it's a primitive data type these bits contain the value of the primitive data type itself, That's why if we change the value of header inside the method then it does not reflect the changes outside.

  • If it's an object data type like Foo foo=new Foo() then in this case copy of the address of the object passes like file shortcut , suppose we have a text file abc.txt at C:\desktop and suppose we make shortcut of the same file and put this inside C:\desktop\abc-shortcut so when you access the file from C:\desktop\abc.txt and write 'Stack Overflow' and close the file and again you open the file from shortcut then you write ' is the largest online community for programmers to learn' then total file change will be 'Stack Overflow is the largest online community for programmers to learn' which means it doesn't matter from where you open the file , each time we were accessing the same file , here we can assume Foo as a file and suppose foo stored at 123hd7h (original address like C:\desktop\abc.txt ) address and 234jdid (copied address like C:\desktop\abc-shortcut which actually contains the original address of the file inside) .. So for better understanding make shortcut file and feel..

As many people mentioned it before, Java is always pass-by-value

Here is another example that will help you understand the difference ( the classic swap example ):

 public class Test { public static void main(String[] args) { Integer a = new Integer(2); Integer b = new Integer(3); System.out.println("Before: a = " + a + ", b = " + b); swap(a,b); System.out.println("After: a = " + a + ", b = " + b); } public static swap(Integer iA, Integer iB) { Integer tmp = iA; iA = iB; iB = tmp; } } 

打印:

Before: a = 2, b = 3
After: a = 2, b = 3

This happens because iA and iB are new local reference variables that have the same value of the passed references (they point to a and b respectively). So, trying to change the references of iA or iB will only change in the local scope and not outside of this method.

I always think of it as "pass by copy". It is a copy of the value be it primitive or reference. If it is a primitive it is a copy of the bits that are the value and if it is an Object it is a copy of the reference.

 public class PassByCopy{ public static void changeName(Dog d){ d.name = "Fido"; } public static void main(String[] args){ Dog d = new Dog("Maxx"); System.out.println("name= "+ d.name); changeName(d); System.out.println("name= "+ d.name); } } class Dog{ public String name; public Dog(String s){ this.name = s; } } 

output of java PassByCopy:

name= Maxx
name= Fido

Primitive wrapper classes and Strings are immutable so any example using those types will not work the same as other types/objects.

I have created a thread devoted to these kind of questions for any programming languages here .

Java is also mentioned . Here is the short summary:

  • Java passes it parameters by value
  • "by value" is the only way in java to pass a parameter to a method
  • using methods from the object given as parameter will alter the object as the references point to the original objects. (if that method itself alters some values)

To make a long story short, Java objects have some very peculiar properties.

In general, Java has primitive types ( int , bool , char , double , etc) that are passed directly by value. Then Java has objects (everything that derives from java.lang.Object ). Objects are actually always handled through a reference (a reference being a pointer that you can't touch). That means that in effect, objects are passed by reference, as the references are normally not interesting. It does however mean that you cannot change which object is pointed to as the reference itself is passed by value.

Does this sound strange and confusing? Let's consider how C implements pass by reference and pass by value. In C, the default convention is pass by value. void foo(int x) passes an int by value. void foo(int *x) is a function that does not want an int a , but a pointer to an int: foo(&a) . One would use this with the & operator to pass a variable address.

Take this to C++, and we have references. References are basically (in this context) syntactic sugar that hide the pointer part of the equation: void foo(int &x) is called by foo(a) , where the compiler itself knows that it is a reference and the address of the non-reference a should be passed. In Java, all variables referring to objects are actually of reference type, in effect forcing call by reference for most intends and purposes without the fine grained control (and complexity) afforded by, for example, C++.

A few corrections to some posts.

C does NOT support pass by reference. It is ALWAYS pass by value. C++ does support pass by reference, but is not the default and is quite dangerous.

It doesn't matter what the value is in Java: primitive or address(roughly) of object, it is ALWAYS passed by value.

If a Java object "behaves" like it is being passed by reference, that is a property of mutability and has absolutely nothing to do with passing mechanisms.

I am not sure why this is so confusing, perhaps because so many Java "programmers" are not formally trained, and thus do not understand what is really going on in memory?

In Java only references are passed and are passed by value:

Java arguments are all passed by value (the reference is copied when used by the method) :

In the case of primitive types, Java behaviour is simple: The value is copied in another instance of the primitive type.

In case of Objects, this is the same: Object variables are pointers (buckets) holding only Object's address that was created using the "new" keyword, and are copied like primitive types.

The behaviour can appear different from primitive types: Because the copied object-variable contains the same address (to the same Object) Object's content/members might still be modified within a method and later access outside, giving the illusion that the (containing) Object itself was passed by reference.

"String" Objects appear to be a perfect counter-example to the urban legend saying that "Objects are passed by reference":

In effect, within a method you will never be able, to update the value of a String passed as argument:

A String Object, holds characters by an array declared final that can't be modified. Only the address of the Object might be replaced by another using "new". Using "new" to update the variable, will not let the Object be accessed from outside, since the variable was initially passed by value and copied.

Java has only pass by value. A very simple example to validate this.

 public void test() { MyClass obj = null; init(obj); //After calling init method, obj still points to null //this is because obj is passed as value and not as reference. } private void init(MyClass objVar) { objVar = new MyClass(); } 

It's really quite, quite simple:

For a variable of primitive type (eg. int , boolean , char , etc…), when you use its name for a method argument, you are passing the value contained in it ( 5 , true , or 'c' ). This value gets "copied", and the variable retains its value even after the method invocation.

For a variable of reference type (eg. String , Object , etc…), when you use its name for a method argument, you are passing the value contained in it ( the reference value that "points" to the object ). This reference value gets "copied", and the variable retains its value even after the method invocation. The reference variable keeps "pointing" to the same object.

Either way, you're always passing stuff by value.


Compare this to say C++ where you can have a method to take an int& , or in C# where you could have take a ref int (although, in this case, you also have to use the ref modifier when passing the variable's name to the method.)