How to properly copy objects [duplicate] - java

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.

Related

Java is always pass by value so why am I getting reference when using Array.get(index)? [duplicate]

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

Does Java really always copy all objects passed to a method? [duplicate]

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 7 years ago.
Java is pass-by-value. This means that a called method acts on a copy of an object that was passed in, not on the original object.
If the object is not changed in the method, creating an actual copy seems unnecessary. So a compiler that implements the program to create such a copy would be pretty inefficient. Are all Java compilers (javac, gcj, ECJ, etc.) really doing that?
At least in the case where a parameter is declared final it would make a lot of sense not to copy.
EDIT
OK, so objects are not copied. I got confused because String is special in that it is copied (immutable). Sorry about my unknowings. Just to make up for it, here is a thousandth example of what happens when an object is passed:
import java.lang.System;
class C { int member; }
public class Test {
static void subMethod(C object) { object.member=1; }
public static void main(String[] args) {
C object = new C();
object.member=0;
subMethod(object);
System.out.println(object.member); // prints "1"
}
}
Yes, Java is always pass-by-value. But for objects, it passes the reference value. In other words, the object isn't copied, but its reference is. Changing an object's attributes inside a method changes it outside the method as well.
From here,
However, Objects are not passed by reference. A correct statement would be Object references are passed by value.
On-topic: the compiler simply copies the reference to its chunk of memory in the stack.
Objects in Java are references, and it is this reference which is passed by value; meaning Java is pass-by-reference with objects for practical purposes.
EDIT
It seems my use of the term 'practical purposes' is causing a lot of controversy, so let me clarify. I simply meant that what most people think of when they think of 'pass-by-reference' is that changes to the passed in value are persisted outside of that method, which is the case in Java. e.g.
void someMethod(SomeClass a) {
a.mutateState();
}
SomeClass a = new SomeClass();
someMethod(a); //passes reference to a by value;
a.methodInvolvingSomeState(); //mutations of object state persist to here, as if the previous call were pass-by-reference.
That's all I meant by 'for practical purposes'; OP was under the impression that a copy of a was made, which I was trying to explain was not true. I am fully aware that java is always pass-by-value, hence explicitly stating that it is the reference that is passed by value. As has been pointed out in the comments there are plenty of occasions where it is not the same as if it were actually pass-by-reference, and it was not my intention to indicate that any of those were possible in Java.

what exactly happen in jvm when i create an object in java?

To my understanding if i am writing
Car a3=new Car()
This statement will create a handle named a3 in jvm stack with all its properties in JVM heap.
IF this is correct i am wondering how call by value works.
So, if i create a method checkMethod(Car c) and call it by saying checkMethod(a3);
suppose our car is
public class Car{
int a=0;
public int getpar(){
return a;
}
}
in checkMethod i try to access a using a3.a = 5; so i changed the value of a3.a
it will show me in the calling class as well as it was pointing to the same fields that jvm created in the heap.
But when i do a3= null; in the calling method and go back again in the method from which i was calling
checkMethod(a3) and try to see this object it is not null?
Why it behaved differently as compared to property of object that is a???
checkMethod(a3);
Pass a copy of a value which is a reference to object instance of Car
Inside method...
a3.a = 5
Using a3, modify object instance of Car which is identified by a3 ( which is a copy of original a3).
a3 = null
Set the reference to null ( copy)
When this happens, only the copy you passed to your method will point to null. But the original a3 still points to your object instance of Car.
Why it behaved differently as compared to property of object that is a?
Because Java is (pure) call by value. You cannot manipulate the value of the parameter within the callee context. You always gets a local copy in the calling context.
On method calls, Java passes a copy of the reference.
So when setting a3 to null, it only set its copy of the reference to null and the other copies that are stored else where.
The whole trick is this: Java passes references by value :)

Recursive pass in object by reference? JAVA

So I have an algorithm that forces me to pass in an object as a parameter recursively and on different depths of the recursion it sets the values of the object. The problem is Java isn't allowing me to do this because they pass in by value or something else that is just messing me up. How can you make sure that the object passed in retains the value set?
You never pass an object as an argument in Java. You either pass a reference or a primitive value. The argument is always passed by value. Java doesn't have pass-by-reference at all.
If you're passing in a reference to an object, and you want to make sure the code you call doesn't change the data within that object, your options are:
Create a copy and pass in a reference to that instead
Make your type immutable in the first place.
EDIT: Just to make it clear, if you have:
Foo f = new Foo();
then the value of f is not a Foo object. It's a reference to a Foo object. If you now call:
doSomething(f);
then the value of f is copied as the original value of the parameter within doSomething. That behaviour is basically the definition of pass-by-value. There's nothing doSomething can to do change the value of f - it will still refer to the same object afterwards. The data within that object may have changed, but it won't be a different object.
In a real-world analogy: if I give you a copy of my address, you can go and paint the front door, but you can't change where I live.
As Jon states, all non-primitives are passed by passing a copy of the reference. You don't have a choice. So your recursive method should be able to update the object if it is mutable. HOWEVER, you can't reassign a reference and expect it to propagate back up the call stack. And remember that Strings are not mutable.
In other words, if you do the following, you have not changed the object that was passed:
void myMethod(Object o){
o = new Object();
}
The above changes the local reference to o but does not change the caller's reference to o. If you need to do something like this you would need to return o.

Java is NEVER pass-by-reference, right?...right? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is Java “pass-by-reference”?
I found an unusual Java method today:
private void addShortenedName(ArrayList<String> voiceSetList, String vsName)
{
if (null == vsName)
vsName = "";
else
vsName = vsName.trim();
String shortenedVoiceSetName = vsName.substring(0, Math.min(8, vsName.length()));
//SCR10638 - Prevent export of empty rows.
if (shortenedVoiceSetName.length() > 0)
{
if (!voiceSetList.contains("#" + shortenedVoiceSetName))
voiceSetList.add("#" + shortenedVoiceSetName);
}
}
According to everything I've read about Java's behavior for passing variables, complex objects or not, this code should do exactly nothing. So um...am I missing something here? Is there some subtlety that was lost on me, or does this code belong on thedailywtf?
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 passes references by value, so you get a copy of the reference, but the referenced object is the same. Hence this method does modify the input list.
The references themselves are passed by value.
From Java How to Program, 4th Edition by Deitel & Deitel: (pg. 329)
Unlike other languages, Java does not allow the programmer to choose whether to pass
each argument by value or by reference. Primitive data type variables are always passed
by value. Objects are not passed to methods; rather, references to objects are passed to
methods. The references themselves are passed by value—a copy of a reference is passed
to a method. When a method receives a reference to an object, the method can manipulate
the object directly.
Used this book when learning Java in college. Brilliant reference.
Here's a good article explaining it.
http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html
Well, it can manipulate the ArrayList - which is an object... if you are passing an object reference around (even passed by value), changes to that object will be reflected to the caller. Is that the question?
I think you are confused because vsName is modified. But in this context, it is just a local variable, at the exact same level as shortenedVoiceSetName.
It's not clear to me what the exact question within the code is. Java is pass-by-value, but arrays are pass-by-reference as they pass no object but only pointers! Arrays consist of pointers, not real objects. This makes them very fast, but also makes them dangerous to handle. To solve this, you need to clone them to get a copy, and even then it will only clone the first dimension of the array.
For more details see my answer here: In Java, what is a shallow copy? (also see my other answers)
By the way, there are some advantages as arrays are only pointers: you can (ab)use them as synchronized objects!

Categories

Resources