This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 8 years ago.
I'm familiar with Call by reference concept in java but after seeing this code I'm confused
public class App
{
public static void main( String[] args )
{
Test t1 = new Test(1);
Test t2 = new Test(8);
App.doSomething(t1, t2);
System.out.print(t1.a);
System.out.print(t2.a);
}
public static void doSomething(Test t1, Test t2){
System.out.print(t1.a++);
System.out.print(t2.a++);
t1 = new Test(999);
t2 = new Test(888);
}
}
Prints:
1
8
2
9
Why does'nt value of "t1.a" and "t1.b" in the main function change to 888 and 999?
Java does not have call by reference. All parameters are passed by value -- but in the case of a parameter that is an object, the "value" that is passed is a reference to the object.
As a result, if you use the local reference to that object within the method to modify the object, it will modify the same object. However, if you assign something to that local variable, then it no longer has a reference to the original object, and subsequent changes will not affect the original object.
Thats why you typically set your method arguments to final - to avoid this kind of confusion :) findbugs would actually produce a style warning about this effect
That's because in java arguments are always pass-by-value.
In your example you pass a reference to a object, however this reference is passed by value. In other words, new local variable t1 is created and initialized with the references to your object that has been passed in the argument. So when you assign new Test() to it, only the local variable references the new object.
In Java everything is pass by value. The scopes of the 2 t1's and t2's are different. One is in the scope of main() and the other is in the scope of doSomething(). So the reason it isn't changed to 888 or 999 is because those values don't exist once you leave doSomething().
Novices have a hard time with this, I'll try to explain in story form:
If I let you borrow my sticky note (with my name on the top) with an arrow that points to the red sofa, and you take my sticky note and erase my arrow and put on a new arrow to the green sofa. When you finish your shenanigans, I will have a sticky note with my name on it that points to the green sofa. My stickynote was changed.
If however, I let you borrow my sticky note with my name on it, which has an arrow that points to the red sofa, and you take my sticky note and set it to the side, and you make a new sticky note with your name on it, then you put an arrow on it pointing to the green sofa, and you finish your shenanigans, then my sticky note is unchanged with my name pointing to the red sofa. You created your sticky note that I can't reach.
When you crammed a new object into t1, you didn't destroy the old one because you do not have authorization to do so. You simply pushed it to the side, and created a new one, which nobody has access to except you.
This line:
t1 = new Test(999);
Does not erase the old t1. You simply make a new t1 that is only local to the method, which is garbage collected after the method ends. With this line, you didn't change the parameter passed in, you created a new variable with the same name.
Related
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 9 months ago.
I'm Ryan who's a rookie in programming. I was going through the OOP part of my textbook today and I found a part that I won't understand at all. There are 2 codes, I'll have them copied here.
The first one is :
public class Change {
public static void main(String[] args) {
int x = 17;
dontChange(x);
System.out.println(x);
}
static void dontChange(int z) {
z = 42;
}
}
When the code was executed. The output would still be 17, which is not the expected 42(in my understanding of parameter and Method.)
The textbook provided another example as well, which results in a change.
public class Change {
void change(Student s) {//student is a type
s.name = "Fred";
public static void main(String[] args) {
stu.name = "Jane";
change(stu);
System.out.println(stu.name);
}
}
This code would result in the output the name as 'Fred', I was wondering where's the difference between them and what was the reason behind these codes when they look similar and worked totally differently.
Thank you for going through the whole post, I wish you have a great day!
You need to distinguish between “passing by value” and “passing by reference”. Maybe this helps
If you want to understand the answer to this Question, why the value does not change, you have to understand, why the value sometimes change.
The values changes,if the Datatyp is referencial. This means, that the data is stored at the heap(a part of memory) and our variable only points to this data. This means, that your variable only stores, where the data is really stored.
If we change our data,we are following our reference and change it there.
This means, that every reference, which points at our data is also changed. It is the same object.
What happens here is different. You are not dealing with referencial Datatyps.
You are dealing with primitives(int, float, char....). Those datatyps aren't stored in the heap. They are stored in the stack(another part of memory). This means, that the data is really stored in our variable. So, if we change our data in our variable, we aren't following an reference and change it there. We are really changing the value in our variable.
An analogy:
Referencial types are like notes, which point to a different note. In the second note is the data. If we try to change the datanote, we take a look at our first note with the reference to the datanote and then change the datanote. Any note pointing to the datanote has now the updated data.
primitives are like, if our first note has all the data. There is no pointing to somewhere else. It is our data
Primitives start most of the time with a lower case letter. Primitives can't have any functions or anything.
Refercal start most of the time with a Capital letter. They can have functions and are most of the time classes
What you wanted to do was to return the new value and set it equal to x.
I hope, i've helped you a bit.
If you have any Questions left, feel free to ask
sorry for my English:)
Firstly, I would point out the difference between the two examples you've shown. The method Change#change(Student)
public class Change {
public void change(Student s) {
s.name = "Fred";
}
}
Compared to Change#dontChange(int)
public class Change {
public void dontChange(int i) {
i = 42;
}
}
The most notable difference between these two methods is where they assign (=) the value they're passing. s.name vs i. Note the presence of the dot operator (.) indicating that there's access of an Object's field or method. This can help start the explanation of why change(Student) updates the value it assigns to as compared to dontChange(int).
There was reference of looking into the difference between pass-by-value and pass-by-reference in other answers, and that will be required information for WHY this happens. However, I think there should be a slightly deeper understanding of what a variable is in java for that to help explain it. The easiest explanation I find is that a variable in java is a number. Period. Always. Now that might seem weird, right? You obviously have an object when you do Student stu = new Student(), but that's only partially correct. You do instantiate (create/construct) an object, but the value stored in Student stu can actually be thought of as a number pointing to a spot in memory where stu's values are stored. There IS a difference in how these number are handled, but they are, in essence, all numbers.
Knowing this, you can work with the thought that values passed to a method in java are always passed-by-value. If you wanted to test this you could see the output of changing the body of Change#change(Student) to
public class Change {
void change(Student s) {
Student newStudent = new Student();
newStudent.name = "Fred";
s = newStudent;
}
}
You may expect the output name to still be "Fred", but it should result in "Jane". We didn't modify the object that Student s refers to, we updated what the variable s points to. The difference being that in the original Change#change(Student) method you assigned the value "Fred" to the name field (s.name) of the object that Student s refers to.
When you call Change#change(Student) with the variable stu the parameter s's value becomes the same identifying number that stu points to, but the variables themselves are entirely different. They only, when s is initialized, have the same value (a number pointing to a space in memory).
It should be noted that assigning "Jane" and "Fred" to the Student's name field is actually assigning a reference to a String which represents "Jane" or "Fred" to the Student's name field. As the name field's type is, assumed to be, String which is not a primitive type. Meaning it's a reference to some String object in memory.
What is happening here is passing by value and passing by reference. In Java all primitive types(int, char...) are passed by value to any method, this means the value of them are copied for the method to use.
Anything else like objects from classes you create are passed by reference. This means the contents of the object are not copied but the address of where that object is in memory is copied to the method. The value at this address(the original object) is then used within the method meaning changes to it are seen outside of the method.
To go into more detail and why this happens can get quite confusing as a beginner but other people have linked good articles to read. To put it simply in my own words.
Whenever you are using an object(non-primitive type) i.e Student. Java is actually seeing this as an address to that object but to keep things easier for the programmer Java doesn't make you declare this in any way. Any access to this object is automatically handled by Java to mean the value of the address you are using.
This question already has answers here:
What's the difference between passing by reference vs. passing by value?
(18 answers)
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 2 years ago.
I was working on this bug in my application and saw something very weird:
selectedService = dataResponse.getServices().get(position);
selectedService.setPrice(3000);
dataResponse.getServices().get(position).getPrice(); // Returns 3000 which should be 0
Shouldn't the get method copy the object into selectedService? If not how to copy it?
No, it shouldn't.
Java is always pass-by-value, but that value itself is a reference. So if you call a method which alters data of that particular object, it is reflected to all methods retrieving data from that particular object.
A possible solution to this problem is to make immutable types. There are classes which already implement this, for instance, all classes from the java.time package are immutable. All 'setters' of those classes return a fresh copy of the instance, with the specified value set. An example may be LocalDate::plusDays.
Here is a little example of the difference between pass-by-value and pass-by-reference.
Take a look at this code.
void main() {
Dog myLittleDog = new Dog("Brutus");
change(myLittleDog);
System.out.println(myLittleDog.getName());
}
void change(Dog aDog) {
aDog = new Dog("Jack");
}
What happens here? We pass our dog named "Brutus" to the change method. Within this method, we replace Brutus with a new Dog named "Jack". If we print the name of myLittleDog, what will be his name? Will it be "Jack"?
The answer is no. The value of the reference to the dog is copied, and is available within the change method under the name aDog. Both myLittleDog and aDog are referring to the same actual dog object in memory. But now the change method reassigns aDog with a new object. At this moment, the variables myLittleDog and aDog both refer to distinct objects. Once the change method exits, the variable aDog is unreachable and Jack is garbage collected. myLittleDog is still called "Brutus".
Conversely, this wouldn't be the case if Java was pass-by-reference. Then reassignment of aDog would also mean reassignment of myLittleDog.
See also: What's the difference between passing by reference vs. passing by value?
But then why is my selectedService still mutated?
Although values of references are copied when they are passed to methods, doesn't that mean that objects cannot change (that is, be modified). Suppose I give you a copy of my house key. You access my house and move the couch to the kitchen. Then if I enter my house, I will see that the couch has been moved. The reference value is copied, but everyone accessing the referenced object (the house), will see modifications to it.
selectedService here is a reference variable which points to whatever object you assign to it. While assigning dataResponse.getServices().get(position) to selectedService it appears as if you're assigning an object to it, however, what you're actually assigning is the reference to the original object.
As quoted on https://www.geeksforgeeks.org/clone-method-in-java-2/
Unlike C++, in Java, if we use assignment operator then it will create a copy of reference variable and not the object
To create a copy of the object
Use the clone() method to create a copy of the object as in
selectedService = (SelectedServiceClass) dataResponse.getServices().get(position).clone();
UPDATE
public Fish mate(Fish other){
if (this.health > 0 && other.health > 0 && this.closeEnough(other)){
int babySize = (((this.size + other.size) /2));
int babyHealth = (((this.health + other.health) /2));
double babyX = (((this.x + other.x) /2.0));
double babyY = (((this.y + other.y) /2.0));
new Fish (babySize, babyHealth, babyX, babyY);
}
return null;
}
When new Fish is called, is there a new instance of Fish floating around somewhere without a reference or have I just allocated memory for a new Fish without actually instantiating it?
Can I get the new Fish call to create an actual instance of the Fish with a unique reference name other than iterating through a loop?
When new Fish is called, is there a new instance of Fish floating around somewhere without a variable name or have I just allocated memory for a new Fish without actually instantiating it?
A new Fish object will be created, and will be garbage-collected since there is no reference to it.
The garbage collection will take place (sometime) after the constructor of Fish is done.
In your case that doesn't make much sense, but sometimes it does, if instantiating an object will start a new Thread or run some other routines that you want to be run only once.
If I have only allocated memory or there is a Fish without a name, how can I get the new Fish call to create an actual instance of the Fish with a unique variable name?
This is not very clear. But I sense that you just want to return new Fish(...); and assign it to a variable yourself where you call it, something like:
Fish babyFish = femaleFish.mate(maleFish);
"have I just allocated memory for a new Fish without actually instantiating it?"
No. The instance is initialized (the constructor is executed), but if no reference is kept for this instance it will eventually be garbage collected. Keep in mind that a reference can be kept even if your code doesn't do so, for example if the constructor puts this in some static variable.
The following figure's explanation really helped me when I had confusion in the beginning and I hope will help you as well.You can think of Employee as Fish here.
In your case you created a new Fish() object locally inside a method, so the lifetime of that should be assigned locally as well.The garbage collector always looks for unused objects and will identify this suitable for collection as soon as your method exits,along with other locals defined inside the method.
You are returning null, so this method can not be treated as factory method structure since it does not return an instance.I am not sure what you mean by :
Can I get the new Fish call to create an actual instance of the Fish with a unique reference name other than iterating through a loop?
But I think you asked if you can use the exact new Fish() that is inside the method.The short answer is: no. Although you can definitely create another new Fish() but you need a reference variable to retrieve that address or you can return the instance for the method instead of null,which will be a static factory method and is known as a good practice when you want to separately name your constructors.
In a more specific manner to answer both of your updated questions:
1)You did created a new object when you wrote new Fish() but you did not create a reference variable to really retrieve that object information.It's like you have built a house but you don't know the address of the house.Then you can never get to the house. What will happen is because of the lack of retrieval process, this object will be identified as unused by the garbage collector and hence it will be collected.
2)Since there is no reference/pointer or anything to get the information stored in the new object, you cannot retrieve the exact new Fish() inside the method but you can certainly create another object with a reference variable if you really wish to retrieve the information stored in the object.
Lastly, although it is mainly written for C language usage, the following document by Nick Parlante of Stanford University does an exceptional job in explaining references, stack,and heap memories.Click here.
First, let me clear up some confusion in your terminology: An object doesn't have a name. A variable has a name, but you can have many variables of different names all referring to the same object. Having a named variable reference the object does not mean the object has a name.
If you do new Fish() but don't assign the new reference to anything, the new object will be unreachable as soon as the constructor returns.
There is no way to recover that reference, and the object will be unallocated by the next Garbage Collection run.
Trying to fully grasp Java's pass-by-value. Let's say we have this code:
public class Test {
static void switchIt(Test t) {
t = new Test();
}
public static void main(String ... args) {
Test a = new Test();
switchIt(a);
}
}
When the object referenced by a gets passed to switchIt(), the reference value is copied to t. So we'd have two different reference variables, with identical bit-patterns that point to a single object on the heap.
When t = new Test() runs, obviously a still refers to the old object, and t now points to a new object on the heap. Since the a and t reference variables used to have identical bit-patterns, does this mean that Java implicitly changed the bit-pattern of the t reference variable? Or is it wrong to assume that the bit patterns were ever identical to begin with?
Let's say the a reference variable is represented on the stack as 0001. When I pass it to the function, that means t is also represented on the stack as 0001, since I passed a copy of the bits in the reference variable.
When I assign t to a new Test(), if t and a both are represented as 0001 on the stack, would that 0001 change for t?
Think of it this way:
Java isn't passing the object, it's passing the memory pointer of the object. When you create a new object, it gets a new pointer. So when we say java always passes by value, it's because it's always passing the pointer of the object which is a numeric value.
Even though the objects are equal to one another (a.equals(t)) may return true - they are not identical because they have different pointers and are thusly different objects residing in different memory space.
Using your edit example. a would have 0001 but t would be 0002
Is Java "pass-by-reference" or "pass-by-value"?
Hope that helps
Yes, the reference for t would change to point to the newly-allocated Test instance. Your understanding is correct on that point.
When the switchIt() method returns, there are no longer any references to that new object. It is now eligible for garbage collection, while the original object that a continues to reference will not be collectible until main() returns.
I think you got it, but you didn't phrase it too well. Here's a more in depth explanation, though the implementation may not be 100% exactly as I'm describing.
When you compile that code, a structure called a "stack frame" will be created for each of your methods. Each stack frame will hold enough space in it for parameters, local variables and so on. Basically it will have enough resources for your method to do its thing. All these stack frames are placed in "the stack" :)
When you run your code, in main you create a new instance of Test and assign the reference to variable a or, more precisely, to the location in the stack frame reserved for variable a. The actual object will be stored on the heap and your variable a will only hold the memory address of that object, as you already seem to know.
When you call switchIt, the runtime will send a copy of the reference a to the stack frame of the method switchIt. This stack frame has enough space for your parameter and it will store it in its reserved space. But what you're doing in switchIt is replacing the initial value stored in that reserved space with a new reference from a new object that has just been created and placed on the heap. Now you have two objects on the heap, each stack frame containing one of these references.
I think the code will clear you more .Check the hash code in each print statement it is not the memory location but it will help you to understand the answer of your question.
class Ideone
{
static void switchIt(Ideone t) {
System.out.println("Object t "+t); // print statement 2
t = new Ideone();
System.out.println("object t after changing t "+t); // print statement 3
}
public static void main(String[] args) {
Ideone a = new Ideone();
System.out.println("object a "+a); // print statement 1
switchIt(a);
System.out.println("object a after calling switchIt() "+a); // print statement 4
}
}
Output:
object a Ideone#106d69c
Object t Ideone#106d69c
object t after changing t Ideone#52e922
object a after calling switchIt() Ideone#106d69c
print statement 1,2,4 have same hash code but 3 has different hash code.
1. Creating object a
2. Passing a to switchIt(Ideone t):
3. Changing t to new Ideone():
Note:The hash code are not actual memory location.
This question already has answers here:
How do I copy an object in Java?
(23 answers)
Closed 8 years ago.
This might have been asked already but since I am not so sure how to phrase it I could not find it.
Essentially
Suppose we have the class a, (see code below), and we want to copy an instance of it, a1, to another instance a2.
So, in my main I would have a1.copy(a2)
I know that using copy2 method this will work. However copy1 will not. I just would like to clarify why this is. Is it because the parameter is just a "copy" of the object, so the object itself (a2) is not altered.
class a {
private int val;
public class(int val){
this.val = val;
}
public void copy1(a obj){
obj = this;
}
public void copy2(a obj) {
obj.val = this.val;
}
}
The key to understand your problem is that Java's method call is always pass-by-value, not by reference.
When you call a.copy1(b), Java copies a value of b's reference(say it is called b_copy, please note that b_copy points to the same memory location as b), and then pass b_copy to the method copy1.
And in your method of copy1, Java only changes the reference of b_copy.
public void copy1(b_copy){
b_copy=a;
}
So now :
b_copy: b_copy=a;
b: b does not change at all;
When the method ends,b_copy dies. So nothing changes on b!
While a.copy2(b) manipulates on the object itself, but it still copies a new value of b(say b_copy again) and pass into copy2
public void copy2(b_copy){
b_copy.val = a.val;
}
Since b_copy points to the same memory of b, so when you do changes on b_copy.val, you also does the same on b.val itself. That's the reason why b changes.
So now :
b_copy: b_copy, but b_copy's val changes
b: b's val also changes, since b_copy is points to the b's memory location;
And then when method ends, b_copy dies, and b has changed!
You may find more discussion on Is Java "pass-by-reference" or "pass-by-value"?
And you may also need How do I copy an object in Java?
When you call the method copy1(), the parameter is a copy of the reference of the object a obj. When you set it to this (obj = this;) the copy of the reference of the object is replaced by the current object, but the original object and the reference to the object at the place you are calling the copy1() method stays the same. You just change the copy of the reference of the object.
When you call the method copy2(), no reference work is done there, and you are doing one by one matching of the variables (properties of the objects) and there is no copy of reference work there. You are changing the object itself. In this case, this.val = obj.val; would also work.
For more understanding, check this topic and check how other languages like C or C++ handle parameter passing issue.
I think you might want to look into how parameters are passed in Java.
For primitive variables, they are passed by value. If I recall correctly, this means that a temporary value is passed and any changes to the variable in the function update only the temporary variable.
However, objects are passed by reference. This means that instead of the entire object, essentially a pointer to where the object is in memory is passed.
What this means is that updating an object's variables produces lasting effects on that object. Additionally, if you set one object equal to another object, you're really just setting the memory references to be the same (a byproduct of this is that the values of the variables in the objects are then linked).
This explains why the first function fails to do what you want (you're setting the memory locations to be the same). And the second succeeds (you're performing a deep copy into a new memory address).
Your reasoning is correct. When you pass an object to a method (as you do in copy1), all you are doing is creating another reference to the same object. If you override this reference, as copy1 does, it just means that that reference now points to a different object - it does not, and can not, change the original object.