Ccna final exam - java, php, javascript, ios, cshap all in one. This is a collaboratively edited question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.
Friday, May 25, 2012
Is Java pass-by-reference?
I always thought Java was pass-by-reference, however I've seen a couple of blog posts (e.g. this blog ) that claim it's not. I don't think I understand the distinction they're making.
Hey there -- just noticed you referenced my article ;)
The Java Spec says that everything in Java is pass-by-value. There is no such thing as "pass-by-reference" in Java.
The key to understanding this is that something like
Dog myDog;
is not a Dog; it's actually a pointer to a Dog.
What that means, is when you have
Dog myDog = new Dog("Rover"); foo(myDog);
you're essentially passing the address of the created Dog object to the foo method.
(I say essentially b/c Java pointers aren't direct addresses, but it's easiest to think of them that way)
Suppose the Dog object resides at memory address 42. This means we pass 42 to the method.
if the Method were defined as
public void foo(Dog someDog) { someDog.setName("Max"); // AAA someDog = new Dog("Fifi"); // BBB someDog.setName("Rowlf"); // CCC }
let's look at what's happening.
the parameter someDog is set to the value 42 at line "AAA"
someDog is followed to the Dog it points to (the Dog object at address 42) that Dog (the one at address 42) is asked to change his name to Max
at line "BBB"
a new Dog is created. Let's say he's at address 74 we assign the parameter someDog to 74
at line "CCC"
someDog is followed to the Dog it points to (the Dog object at address 74) that Dog (the one at address 74) is asked to change his name to Rowlf
then, we return
Now let's think about what happens outside the method:
Did myDog change?
There's the key.
Keeping in mind that myDog is a pointer, and not an actual Dog, the answer is NO. myDog still has the value 42; it's still pointing to the original Dog.
It's perfectly valid to follow an address and change what's at the end of it; that does not change the variable, however.
Java works exactly like C. You can assign a pointer, pass the pointer to a method, follow the pointer in the method and change the data that was pointed to. However, you cannot change where that pointer points.
In C++, Ada, Pascal and other languages that support pass-by-reference, you can actually change the variable that was passed.
If Java had pass-by-reference semantics, the foo method we defined above would have changed where myDog was pointing when it assigned someDog on line BBB.
Think of reference parameters as being aliases for the variable passed in. When that alias is assigned, so is the variable that was passed in.
Does that help? (I'll have to add this as an addendum to my article...) -- Scott
This will give you some insights of how Java really works to the point that in your next discussion about Java passing by reference or passing by value you'll just smile :-)
Step one please erase from your mind that word that starts with 'p' "_ _ _ _ _ _ _", especially if you come from other programming languages. Java and 'p' cannot be written in the same book, forum, or even txt.
Step two remember that when you pass an Object into a method you're passing the Object reference and not the Object itself.
Student: Master, does this mean that Java is pass-by-reference? Master: Grasshopper, No.
Now think of what an Object's reference/variable does/is:
A variable holds the bits that tell the JVM how to get to the referenced Object in memory (Heap). When passing arguments to a method you ARE NOT passing the reference variable, but a copy of the bits in the reference variable. Something like this: 3bad086a. 3bad086a represents a way to get to the passed object. So you're just passing 3bad086a that it's the value of the reference. You're passing the value of the reference and not the reference itself (and not the object). This value is actually COPIED and given to the method.
In the following (please don't try to compile/execute this...):
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. }
What happens?
The variable person is created in line #1 and it's null at the beginning. A new Person Object is created in line #2, stored in memory, and the variable person is given the reference to the Person object. That is, its address. Let's say 3bad086a. The variable person holding the address of the Object is passed to the function in line #3. In line #4 you can listen to the sound of silence Check the comment on line #5 A method local variable -anotherReferenceToTheSamePersonObject- is created and then comes the magic in line #6:
The variable/reference person is copied bit-by-bit and passed to anotherReferenceToTheSamePersonObject inside the function. No new instances of Person are created. Both "person" and "anotherReferenceToTheSamePersonObject" hold the same value of 3bad086a. Don't try this but person==anotherReferenceToTheSamePersonObject would be true. Both variables have IDENTICAL COPIES of the reference and they both refer to the same Person Object, the SAME Object on the Heap and NOT A COPY.
A picture is worth a thousand words:
Note that the anotherReferenceToTheSamePersonObject arrows is directed towards the Object and not towards the variable person!
If you didn't get it then just trust me and remember that it's better to say that Java is pass by value. Well, pass by reference value. Oh well, even better is pass-by-copy-of-the-variable-value! ;)
Now feel free to hate me but note that given this there is no difference between passing primitive data types and Objects when talking about method arguments.
You always pass a copy of the bits of the value of the reference!
If it's a primitive data type these bits will contain the value of the primitive data type itself. If it's an Object the bits will contain the value of the address that tells the JVM how to get to the Object.
Java is pass-by-value because inside a method you can modify the referenced Object as much as you want but no matter how hard you try you'll never be able to modify the passed variable that will keep referencing (not p _ _ _ _ _ _ _) the same Object no matter what!
The changeName function above will never be able to modify the actual content (the bit values) of the passed reference. In other word changeName cannot make Person person refer to another Object.
Of course you can cut it short and just say that Java is pass-by-value!
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 a a 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.
I can't believe that nobody mentioned Barbara Liskov yet. When she designed CLU in 1974, she ran into this same terminology problem, and she invented the term call by sharing (also known as call by object-sharing and call by object) for this specific case of "call by value where the value is a reference".
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 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. For example:
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 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.
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.
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 value, 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 e.g. C++.
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.
Just to show the contrast, compare the following c++ and java snippets:
In C++: Note: Bad code - memory leaks! But it demonstrates the point.
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("newObjRegPtr"); // 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" }
In 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 only has the two types of passing: by value for built-in types, and by value of the pointer for object types.
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?
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.
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.
You can look at http://java.sun.com/docs/books/tutorial/java/javaOO/arguments.html
Passing Reference Data Type Arguments
Reference data type parameters, such as objects, are also passed into methods by value. This means that when the method returns, the passed-in reference still references the same object as before. However, the values of the object's fields can be changed in the method, if they have the proper access level. For example, consider a method in an arbitrary class that moves Circle objects:
public void moveCircle(Circle circle, int deltaX, int deltaY) { // code to move origin of circle to x+deltaX, y+deltaY circle.setX(circle.getX() + deltaX); circle.setY(circle.getY() + deltaY);
//code to assign a new reference to circle circle = new Circle(0, 0); }
Let the method be invoked with these arguments:
moveCircle(myCircle, 23, 56)
Inside the method, circle initially refers to myCircle. The method changes the x and y coordinates of the object that circle references (i.e., myCircle) by 23 and 56, respectively. These changes will persist when the method returns. Then circle is assigned a reference to a new Circle object with x = y = 0. This reassignment has no permanence, however, because the reference was passed in by value and cannot change. Within the method, the object pointed to by circle has changed, but, when the method returns, myCircle still references the same Circle object as before the method was called.
Java copies the reference by value. So if you change it to something else (e.g, using new) the reference does not change outside the method. For native types, it is always pass by value.
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; } }
Prints:
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.
If you create a method which receives an int for example and change the value within the method, the caller will not see the value you've just assigned.
int value = 1; invokeSomeMethod( value ); // value get assigned with value 9 System.out.println( value ); // value printed will be 1
However, you can still an object which encapsulate a primitive value
SomeObject obj = new SomeObject(); obj.setValue(1); invokeSomeMethod( obj ); // obj.setValue(9) is invoked here System.out.println( obj.getValue() ); // value printed will be 9
So Java is not by reference when dealing with first-level objects (like primitives) but for real objects, you can actually change it's internal values (using getter/setter) and the caller's object will be affected.
Pass by reference, as the blog you referenced seems to discuss it, I believe refers to languages that will not evaluate arguments to function unstil the argumants are actually used. Java eagerly evaluates the arguments to its functions (aka methods), though.
For example, suppose you have a method like this:
int add(int a, int b) { if (b == 0) { return a; } else { return a + b; } }
And you want to call it like this:
add(getFirstArg(), getSecondArg());
Since both arguments in this call are themselves calls to other methods, Java will first evaluate them, so that it knows what arguments to give to add(). In other words, it determines what values to pass to add(). In pass by value, the arguments are always evaluated, even if they don't need to be. If Java used pass by reference, and getSecondArg() evaluated to 0, then getFirstArg would never be evaluated. It's reference would just be returned as the result of add().
Does that make it more clear, or did I just manage to muddy the waters some more?
it's a bit hard to understand, but java always copies the value - the point is, normally the value is a reference. therefore you end up with the same object without thinking about it...
In my opinion, "pass by value" is a terrible way to singularly describe two similar but different events. I guess they should have asked me first.
With primitives we are passing the actual value of the primitive into the method (or constructor), be it the integer "5", the character "c", or what have you. That actual value then becomes its own local primitive. But with objects, all we are doing is giving the same object an additional reference (a local reference), so that we now have two references pointing to the same object.
public class ParamPassDemo { public static void main(String[] args) { A a =new A();//Create an object of A a.i=10; change(a); System.out.println(a.i); //Guess result of print statement } private static void change(A a){ a=null; //assign null }
Java is always pass-by-value. The difficult thing can be to understand that Java passes objects as references passed by value.
ReplyDeleteIt goes like this:
public void foo(Dog d) {
d.name.equals("Max"); // true
d = new Dog("Fifi");
d.name.equals("Fifi"); // true
}
Dog aDog = new Dog("Max");
foo(aDog);
aDog.name.equals("Max"); // true
In this example aDog.name will still be "Max". "d" is not overwritten in the function as the object reference is passed by value.
Likewise:
public void foo(Dog d) {
d.name.equals("Max"); // true
d.setname("Fifi");
}
Dog aDog = new Dog("Max");
foo(aDog);
aDog.name.equals("Fifi"); // true
Hey there -- just noticed you referenced my article ;)
ReplyDeleteThe Java Spec says that everything in Java is pass-by-value. There is no such thing as "pass-by-reference" in Java.
The key to understanding this is that something like
Dog myDog;
is not a Dog; it's actually a pointer to a Dog.
What that means, is when you have
Dog myDog = new Dog("Rover");
foo(myDog);
you're essentially passing the address of the created Dog object to the foo method.
(I say essentially b/c Java pointers aren't direct addresses, but it's easiest to think of them that way)
Suppose the Dog object resides at memory address 42. This means we pass 42 to the method.
if the Method were defined as
public void foo(Dog someDog) {
someDog.setName("Max"); // AAA
someDog = new Dog("Fifi"); // BBB
someDog.setName("Rowlf"); // CCC
}
let's look at what's happening.
the parameter someDog is set to the value 42
at line "AAA"
someDog is followed to the Dog it points to (the Dog object at address 42)
that Dog (the one at address 42) is asked to change his name to Max
at line "BBB"
a new Dog is created. Let's say he's at address 74
we assign the parameter someDog to 74
at line "CCC"
someDog is followed to the Dog it points to (the Dog object at address 74)
that Dog (the one at address 74) is asked to change his name to Rowlf
then, we return
Now let's think about what happens outside the method:
Did myDog change?
There's the key.
Keeping in mind that myDog is a pointer, and not an actual Dog, the answer is NO. myDog still has the value 42; it's still pointing to the original Dog.
It's perfectly valid to follow an address and change what's at the end of it; that does not change the variable, however.
Java works exactly like C. You can assign a pointer, pass the pointer to a method, follow the pointer in the method and change the data that was pointed to. However, you cannot change where that pointer points.
In C++, Ada, Pascal and other languages that support pass-by-reference, you can actually change the variable that was passed.
If Java had pass-by-reference semantics, the foo method we defined above would have changed where myDog was pointing when it assigned someDog on line BBB.
Think of reference parameters as being aliases for the variable passed in. When that alias is assigned, so is the variable that was passed in.
Does that help? (I'll have to add this as an addendum to my article...)
-- Scott
This will give you some insights of how Java really works to the point that in your next discussion about Java passing by reference or passing by value you'll just smile :-)
ReplyDeleteStep one please erase from your mind that word that starts with 'p' "_ _ _ _ _ _ _", especially if you come from other programming languages. Java and 'p' cannot be written in the same book, forum, or even txt.
Step two remember that when you pass an Object into a method you're passing the Object reference and not the Object itself.
Student: Master, does this mean that Java is pass-by-reference?
Master: Grasshopper, No.
Now think of what an Object's reference/variable does/is:
A variable holds the bits that tell the JVM how to get to the referenced Object in memory (Heap).
When passing arguments to a method you ARE NOT passing the reference variable, but a copy of the bits in the reference variable. Something like this: 3bad086a. 3bad086a represents a way to get to the passed object.
So you're just passing 3bad086a that it's the value of the reference.
You're passing the value of the reference and not the reference itself (and not the object).
This value is actually COPIED and given to the method.
In the following (please don't try to compile/execute this...):
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. }
What happens?
The variable person is created in line #1 and it's null at the beginning.
A new Person Object is created in line #2, stored in memory, and the variable person is given the reference to the Person object. That is, its address. Let's say 3bad086a.
The variable person holding the address of the Object is passed to the function in line #3.
In line #4 you can listen to the sound of silence
Check the comment on line #5
A method local variable -anotherReferenceToTheSamePersonObject- is created and then comes the magic in line #6:
The variable/reference person is copied bit-by-bit and passed to anotherReferenceToTheSamePersonObject inside the function.
No new instances of Person are created.
Both "person" and "anotherReferenceToTheSamePersonObject" hold the same value of 3bad086a.
Don't try this but person==anotherReferenceToTheSamePersonObject would be true.
Both variables have IDENTICAL COPIES of the reference and they both refer to the same Person Object, the SAME Object on the Heap and NOT A COPY.
A picture is worth a thousand words:
Note that the anotherReferenceToTheSamePersonObject arrows is directed towards the Object and not towards the variable person!
If you didn't get it then just trust me and remember that it's better to say that Java is pass by value. Well, pass by reference value. Oh well, even better is pass-by-copy-of-the-variable-value! ;)
Now feel free to hate me but note that given this there is no difference between passing primitive data types and Objects when talking about method arguments.
You always pass a copy of the bits of the value of the reference!
If it's a primitive data type these bits will contain the value of the primitive data type itself.
If it's an Object the bits will contain the value of the address that tells the JVM how to get to the Object.
Java is pass-by-value because inside a method you can modify the referenced Object as much as you want but no matter how hard you try you'll never be able to modify the passed variable that will keep referencing (not p _ _ _ _ _ _ _) the same Object no matter what!
The changeName function above will never be able to modify the actual content (the bit values) of the passed reference. In other word changeName cannot make Person person refer to another Object.
Of course you can cut it short and just say that Java is pass-by-value!
Java passes references by value.
ReplyDeleteSo you can't change the reference that gets passed in.
For primitives (int, long etc) it is pass by value the actual value (e.g. 3)
ReplyDeleteFor Objects you pass by value the reference to the object.
So if you have doSomething(foo) and public void doSomething(Foo foo) { .. } the two Foos have copied references that point to the same objects.
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.
ReplyDeleteUsually in Java reference means a a 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.
I can't believe that nobody mentioned Barbara Liskov yet. When she designed CLU in 1974, she ran into this same terminology problem, and she invented the term call by sharing (also known as call by object-sharing and call by object) for this specific case of "call by value where the value is a reference".
ReplyDeleteJava passes references to objects by value.
ReplyDeleteAs 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:
ReplyDeletepublic 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. For example:
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.
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.
ReplyDeleteI have created a thread devoted to these kind of questions for any programming languages here.
ReplyDeleteJava 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.
ReplyDeleteIn 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 value, 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 e.g. C++.
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++:
ReplyDeletevoid 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.
Just to show the contrast, compare the following c++ and java snippets:
ReplyDeleteIn C++: Note: Bad code - memory leaks! But it demonstrates the point.
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("newObjRegPtr"); // 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"
}
In 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 only has the two types of passing: by value for built-in types, and by value of the pointer for object types.
A few corrections to some posts.
ReplyDeleteC 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?
Basically, reassigning Object parameters doesn't affect the argument, e.g.,
ReplyDeleteprivate 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.
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.
ReplyDeletepublic 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.
You can look at http://java.sun.com/docs/books/tutorial/java/javaOO/arguments.html
ReplyDeletePassing Reference Data Type Arguments
Reference data type parameters, such as objects, are also passed into methods by value. This means that when the method returns, the passed-in reference still references the same object as before. However, the values of the object's fields can be changed in the method, if they have the proper access level.
For example, consider a method in an arbitrary class that moves Circle objects:
public void moveCircle(Circle circle, int deltaX, int deltaY) {
// code to move origin of circle to x+deltaX, y+deltaY
circle.setX(circle.getX() + deltaX);
circle.setY(circle.getY() + deltaY);
//code to assign a new reference to circle
circle = new Circle(0, 0);
}
Let the method be invoked with these arguments:
moveCircle(myCircle, 23, 56)
Inside the method, circle initially refers to myCircle. The method changes the x and y coordinates of the object that circle references (i.e., myCircle) by 23 and 56, respectively. These changes will persist when the method returns. Then circle is assigned a reference to a new Circle object with x = y = 0. This reassignment has no permanence, however, because the reference was passed in by value and cannot change. Within the method, the object pointed to by circle has changed, but, when the method returns, myCircle still references the same Circle object as before the method was called.
Java copies the reference by value. So if you change it to something else (e.g, using new) the reference does not change outside the method. For native types, it is always pass by value.
ReplyDeleteHave a look at this code. This code will not throw NullPointerException... It will print "Vinay"
ReplyDeletepublic class Main {
public static void main(String[] args) {
String temp = "Vinay";
print(temp);
System.err.println(temp);
}
private static void print(String temp) {
temp = null;
}
}
If Java is pass by reference then it should have thrown NullPointerException as reference is set to Null.
As many people mentioned it before, Java is always pass-by-value
ReplyDeleteHere 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;
}
}
Prints:
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.
If you create a method which receives an int for example and change the value within the method, the caller will not see the value you've just assigned.
ReplyDeleteint value = 1;
invokeSomeMethod( value ); // value get assigned with value 9
System.out.println( value ); // value printed will be 1
However, you can still an object which encapsulate a primitive value
SomeObject obj = new SomeObject();
obj.setValue(1);
invokeSomeMethod( obj ); // obj.setValue(9) is invoked here
System.out.println( obj.getValue() ); // value printed will be 9
So Java is not by reference when dealing with first-level objects (like primitives) but for real objects, you can actually change it's internal values (using getter/setter) and the caller's object will be affected.
Pass by reference, as the blog you referenced seems to discuss it, I believe refers to languages that will not evaluate arguments to function unstil the argumants are actually used. Java eagerly evaluates the arguments to its functions (aka methods), though.
ReplyDeleteFor example, suppose you have a method like this:
int add(int a, int b) {
if (b == 0) {
return a;
} else {
return a + b;
}
}
And you want to call it like this:
add(getFirstArg(), getSecondArg());
Since both arguments in this call are themselves calls to other methods, Java will first evaluate them, so that it knows what arguments to give to add(). In other words, it determines what values to pass to add(). In pass by value, the arguments are always evaluated, even if they don't need to be. If Java used pass by reference, and getSecondArg() evaluated to 0, then getFirstArg would never be evaluated. It's reference would just be returned as the result of add().
Does that make it more clear, or did I just manage to muddy the waters some more?
it's a bit hard to understand, but java always copies the value - the point is, normally the value is a reference. therefore you end up with the same object without thinking about it...
ReplyDeleteHere is how to make pass by reference work slightly.
ReplyDeletepublic class PassBy {
public static void goodChange(String[] a) {
a[0] = "Pass-by-reference";
}
public static void main(String[] args) {
String[] s2 = new String[]{"Pass-by-value"};
System.out.println(s2[0]);
goodChange(s2);
System.out.println(s2[0]);
}
}
In my opinion, "pass by value" is a terrible way to singularly describe two similar but different events. I guess they should have asked me first.
ReplyDeleteWith primitives we are passing the actual value of the primitive into the method (or constructor), be it the integer "5", the character "c", or what have you. That actual value then becomes its own local primitive. But with objects, all we are doing is giving the same object an additional reference (a local reference), so that we now have two references pointing to the same object.
I hope this simple explanation helps.
Everything is passed by value. Primitives and Object references. But objects can be changed, if their interface allows it.
ReplyDeleteWhen you pass an object to a method, you are passing a reference, and the object can be modified by the method implementation.
void bithday(Person p) {
p.age++;
}
The reference of the object itself, is passed by value: you can reassign the parameter, but the change is not reflected back:
void renameToJon(Person p) {
p = new Person("Jon"); // this will not work
}
jack = new Person("Jack);
renameToJon(jack);
sysout(jack); // jack is unchanged
As matter of effect, "p" is reference (pointer to the object) and can't be changed.
Primitive types are passed by value. Object's reference can be considered a primitive type too.
To recap, everything is passed by value.
this is another nice example i found
ReplyDeletepackage com.lac.faq;
class A {
public int i;
}
public class ParamPassDemo {
public static void main(String[] args) {
A a =new A();//Create an object of A
a.i=10;
change(a);
System.out.println(a.i); //Guess result of print statement
}
private static void change(A a){
a=null; //assign null
}
}