Java pass by reference
Java always passes arguments by value NOT by reference.
Let me explain this through an example:
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");
}
}
I will explain this in steps:
Declaring a reference named
f
of typeFoo
and assign it to a new object of typeFoo
with an attribute"f"
.Foo f = new Foo("f");
From the method side, a reference of type
Foo
with a namea
is declared and it's initially assigned tonull
.public static void changeReference(Foo a)
As you call the method
changeReference
, the referencea
will be assigned to the object which is passed as an argument.changeReference(f);
Declaring a reference named
b
of typeFoo
and assign it to a new object of typeFoo
with an attribute"b"
.Foo b = new Foo("b");
a = b
is re-assigning the referencea
NOTf
to the object whose its attribute is"b"
.As you call
modifyReference(Foo c)
method, a referencec
is created and assigned to the object with attribute"f"
.c.setAttribute("c");
will change the attribute of the object that referencec
points to it, and it's same object that referencef
points to it.
I hope you understand now how passing objects as arguments works in Java :)
Can I pass parameters by reference in Java?
Java is confusing because everything is passed by value. However for a parameter of reference type (i.e. not a parameter of primitive type) it is the reference itself which is passed by value, hence it appears to be pass-by-reference (and people often claim that it is). This is not the case, as shown by the following:
Object o = "Hello";
mutate(o)
System.out.println(o);
private void mutate(Object o) { o = "Goodbye"; } //NOT THE SAME o!
Will print Hello
to the console. The options if you wanted the above code to print Goodbye
are to use an explicit reference as follows:
AtomicReference<Object> ref = new AtomicReference<Object>("Hello");
mutate(ref);
System.out.println(ref.get()); //Goodbye!
private void mutate(AtomicReference<Object> ref) { ref.set("Goodbye"); }
Java Pass By Value and reference
You're incrementing x
twice, but on different dogs. Look at this code:
public static void foo(Dog d) {
++d.x;
d = new Dog("Taz");
++d.x;
}
Initially, d
refers to the dog with a name of Tom
, with x=100
. That isn't a copy of the original object - it's a reference to the same object. Java passes the reference by value, which isn't the same as either passing an object by value or passing an object by reference. It's important to understand that the value of aDog
in main
isn't a Dog
object - it's a reference to a Dog
object. The value of that reference is passed, by value, to your foo
method... so the initial value of d
is the same as the value of aDog
. Further changes to the d
variable itself (rather than the object its value refers to) do not change the aDog
variable.
So, looking at the rest of foo
:
- After the
++d.x
,d
refers to the dog with a name ofTom
, withx=101
. - After
d = new Dog("Taz")
,d
refers to a dog with a name ofTaz
, withx=100
. - After the
++d.x
,d
refers to the dog with a name ofTaz
, withx=101
.
The calling code only ever knows about the dog with a name of Tom
, so it prints out Tom 101.
Java is NEVER pass-by-reference, right?...right?
As Rytmis said, Java passes references by value. What this means is that you can legitimately call mutating methods on the parameters of a method, but you cannot reassign them and expect the value to propagate.
Example:
private void goodChangeDog(Dog dog) {
dog.setColor(Color.BLACK); // works as expected!
}
private void badChangeDog(Dog dog) {
dog = new StBernard(); // compiles, but has no effect outside the method
}
Edit: What this means in this case is that although voiceSetList
might change as a result of this method (it could have a new element added to it), the changes to vsName
will not be visible outside of the method. To prevent confusion, I often mark my method parameters final
, which keeps them from being reassigned (accidentally or not) inside the method. This would keep the second example from compiling at all.
Java and C++ pass by value and pass by reference
C++ does not have the same semantics as Java for values and references. At first, every type has the potential to be either passed by copy or by reference or by address (you can however prevent types to be passed by copy by hiding the copy constructor).
The passing type the most closely related to Java's "by reference" passing is by pointer. Here are an example of the three:
void foo(std::string bar); // by copy
void foo(std::string& bar); // by reference
void foo(std::string* bar); // by address
As a side note, passing by copy is always more expensive than passing by reference or pointer for types that are larger than the size of a pointer. For this reason, you may also often prefer to pass by const
reference, which will allow you to read an object without having to copy it.
void foo(const std::string& bar); // by const reference
However, this is all tricky and you need to be aware of Java subtleties to decide correctly what you want in C++. In Java, you're not actually passing objects by references: you are passing object references by copy. That is, if you assign a new object to an argument, the object of the parent scope won't change. In C++, this more closely matches passing objects by address than by reference. Here's an example of how this is important:
// Java using "object references":
public static void foo(String bar)
{
bar = "hello world";
}
public static void main(String[] argv)
{
String bar = "goodbye world";
foo(bar);
System.out.println(bar); // prints "goodbye world"
}
// C++ using "references":
void foo(std::string& bar)
{
bar = "hello world";
}
int main()
{
std::string bar = "goodbye world";
foo(bar);
std::cout << bar << std::endl; // prints "hello world"
}
// C++ using pointers:
void foo(std::string* bar)
{
bar = new std::string("goodbye world");
delete bar; // you don't want to leak
}
int main()
{
std::string bar = "goodbye world";
foo(&bar);
std::cout << bar << std::endl; // prints "hello world"
}
In other words, when you use references in C++, you're really dealing with the same variable you passed. Any change you do to it, even assignations, are reflected to the parent scope. (This is in part due to how C++ deals with the assignation operator.) Using pointers, you get a behavior more closely related to the one you have with Java references at the cost of possibly having to get object addresses through the unary &
operator (see foo(&bar)
in my example), needing to use the ->
operator to access members, and some additional complexity for using operator overloads.
Another notable difference is that since the usage of by-reference arguments is syntactically closely related to the usage of by-copy arguments, functions should be able to assume that the objects you pass by reference are valid. Even though it's usually possible to pass a reference to NULL
, this is very highly discouraged as the only way to do it is to dereference NULL
, which has an undefined behavior. Therefore, if you need to be able to pass NULL
as a parameter, you'll prefer to pass arguments by address rather than by reference.
Most of the time, you'll want to pass by reference instead of by address when you want to modify an argument from a function because it is more "C++ friendly" (unless you need the NULL
value), even though it's not exactly like what Java does.
Related Topics
How to Create a Delay in Swing
Inetaddress.Getlocalhost() Slow to Run (30+ Seconds)
How Are Constructors Called During Serialization and Deserialization
Often Big Numbers Become Negative
How to Ignore Certain Elements When Comparing Xml
Collision Detection Between Two Images in Java
How to Include External Jar on My Netbeans Project
Checking If Unlimited Cryptography Is Available
Using Variables Outside of an If-Statement
How Can a Keylistener Detect Key Combinations (E.G., Alt + 1 + 1)
404 Error Redirect in Spring with Java Config
Eclipse Error ... Cannot Be Resolved to a Type