Confusion about how Java deals with aggregation and referencing [duplicate] - java

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 4 years ago.
I am confused about how Java deals with aggregation within objects, and in particular referencing of objects. It seems like objects will keep a reference to an aggregated object when it is passed as a parameter, rather than copying it like I've been lead to believe.
Say I have a basic class called Foo which contains a string attribute, print function, and setter for the text attribute.
public class Foo {
private String text;
public Foo(String text) {
this.text = text;
}
public void print() {
System.out.println(text);
}
public void setText(String text) {
this.text = text;
}
}
And a class called Bar which contains an attribute of type Foo, and a method called print which calls foos print method.
public class Bar {
private Foo foo;
public Bar(Foo foo) {
this.foo = foo;
}
public void print() {
this.foo.print();
}
}
If I define an instance of Foo, pass it into a new instance of Bar, and then call bars print method it will print "hello" as I expected. However if I then set the text of the original instance of foo to "Edited" using its setter method, bars print method will also print "Edited".
public static void main(String[] args){
Foo foo = new Foo("Hello");
Bar bar = new Bar(foo);
bar.print();
foo.setText("Edited");
bar.print();
}
Console Output
The Bar object appears to be keeping a reference to the Foo object even though I passed it as a parameter. I'm sure I am missing something trivial here, and I just wanted someone to explain this clearly.

"I'm sure I am missing something trivial here"
Not really. What you see is not a bug, it is a feature. Passing objects around in java means passing around references to them. Objects aren't "cloned" unless the code explicitly requests this through .clone(). Searching on this site for "is java pass-by-value or pass-by-reference" should help you find all the detailed explanation you need.

Reference copied, not object
It seems like objects will keep a reference to an aggregated object when it is passed as a parameter, rather than copying it like I've been lead to believe.
No, the object is not copied.
The reference (pointer) is copied when passed as an argument to a method. The object (the referent, the thing to which the pointer points) is not copied.
The pointer is really an address in memory someplace (though not seen as such by us Java programmers). That address, basically a number, is being copied when passed into the other method. But the object is left untouched, unaware of any references.
Here's a diagram of several Cat objects in memory. Three of the five are candidates for garbage-collection because they have no references remaining, no pointers pointing to them. At first Lilly Mae cat has one pointer pointing to it.
Cat c = new Cat( "Lilly Mae" ) ;
The c variable is not holding a Cat, it holds the address elsewhere in memory where you can find the Cat object. Think of that line as saying:
variable-holding-pointer-that-can-only-point-to-objects-of-class-Cat c = instantiate-new-object-of-type-Cat-and-return-a-pointer-to-its-location-in-memory( "Lilly Mae" ) ;
Then we pass that pointer as a argument to another method.
Human h = SubservientHumanLocator.findFirstAvailable() ;
h.feedCat( c ) ; // Passing a copy of the address of Lilly Mae to this other object’s method.
After the reference to the Cat is passed to the Human, we still have only one hungry cat. We did not clone the cat. We now have two references, both pointing to same original Cat object.
Here is a diagram of state before and after the Human::feedCat call.
After calling on the human to feed the cat, the variable c may fall out of scope. After feeding the cat, the Human object h will likely let its copied reference also fall out of scope. Then, if no other references had been made, and with no existing references remaining, our well-fed Cat object will become a candidate for garbage-collection.

Related

Memory address of an empty object in java

This may be fundamental and be voted as off-topic.
However, as a student I have to know some of the fundamentals (which may be also considered non-fundamental).
If I create a new object someObject,
public class foo {
someObject bar;
private class someObject {
int data;
public someObject (int value) {
data = value;
}
}
}
without assigning any values to its field,
the memory address of the object foo seems to be null.
Within my knowledge, this does not make sense.
Isn't every object created regardless of it having data still be assigned to a memory address?
If I'm wrong (most surely), could someone elaborate more on this please?
Pretty simple:
You never create any Object. All you do is declare a variable. There isn't any Object created in the provided line - neither empty nor in any other state - , no memory allocated, except for the reference, which logically points to null.

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.

How to properly copy objects [duplicate]

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.

Pass references by value Java [duplicate]

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 9 years ago.
I have the following code:
public class PassReferenceByValue {
static void modify(String m)
{
m = "Else";
}
public static void main(String [] arg)
{
String actual = "Something";
modify(actual);
System.out.println(actual);
}
}
It will print Something.
I get that Java doesn't pass objects at all. Instead, it creates copy of the reference passed. If i understood correctly, when I call modify(actual) Java creates another reference to the same object. So, now we have two references that reference to the object actual. Now, through the second reference, we modify the object and the object should change. The object actual should change, because through the copied reference we have the same access to the object.
Can somebody explain me where I fail to understand the concept of passing references by value?
static void modify(String m)
{
m = "Else";
System.out.println(m);
}
If you do this m will print Else, it is only the local variable m what is getting assigned to a new value. value of actual in the main method is not getting changed here.
All "variables" in Java are references to address in a memory when the object resides.
So you have:
actual -> String("Something")
after method invocation you have
actual -> String("Something")
and
m -> String("Something")
You are just changing m -> String("Else")
bot not actual -> String("Something")
Where String("...") notation means object String with value "...".
Check this
Java's pass by value and pass by reference is nicely explained
Strings are immutable, but that's a different discussion
You are not modifying the "object" pointed by String reference actual. In the method modify() you are just overwriting the reference to point to a new String object called "Else". Now this doesn't make any "effect" to the object pointed by actual. Hence when you print actual, it still remains the same
Why I am trying to make point 1 is, say your modify method was like below
public void modify(String s) {
s.replaceAll("Some", "Many");
}
Still the actual would have printed "Something" because of String's immutable behavior.
You're changing m which is a local variable only visible within modify() referencing an object. You're creating a new String object with the value "Else" and making m point towards it.
When you then come out of modify() and print actual, it is still a reference to the String object containing the text "Something".

Can objects be passed by value rather than by reference in Java?

Let's consider the following code in Java.
package obj;
final class First
{
public int x;
public First(int x)
{
this.x=x;
}
}
final class Second
{
public Second(First o)
{
o.x=10;
}
}
final public class Main
{
public static void main(String[] args)
{
First f=new First(50);
Second s=new Second(f);
System.out.println("x = "+f.x);
}
}
In the above code, we are supplying a value 50 through the statement First f=new First(50); which is being assigned to a class member x of type int in the constructor body in the class First.
In the class Second, the object f of the class First is being passed through the statement Second s=new Second(f); and we are modifying the value of the instance variable x held in that object to 10 which will affect the original object f because in Java objects are always passed by reference and not by value.
In some specific situations, it may be crucial not to allow such changes to the original objects. Is there any mechanism in Java that may allow us to prevent such modifications? (that might allow us to pass objects by value)
No, the object isn't being passed at all in Second. The reference is being passed by value.
Java always uses pass-by-value, but the value of any expression is only ever a primitive type or a reference - never an object.
It sounds like you want to create a copy of an existing object, then pass a reference to that new object to the method (by value). Quite what constitutes a "copy" will depend on the data in the class. (You may be able to get away with a shallow copy, or you may need to go deeper etc.)
No, there aren't. I would say that your example is not a very good one: if you want to ensure that something doesn't change, don't provide ways to change it. Causing the change to be lost afterwards is misleading at best.
First f=new First(50);
Second s=new Second(f);
in first line you are create a reference variable of Object type First and in 2nd line it is pass to Class Second
So as Jon Skeet say in java "Java always uses pass-by-value, but the value of any expression is only ever a primitive type or a reference - never an object."
And if if u don't want to change the value of property then u must be pass new object of class First
Because if u have a reference of any class then u can change the property of that class ..
Or u can create a copy of that object which is at the end creating a new object of First Class

Categories

Resources