If I have an instance of an object, and within that object is a variable that holds the data of another object. If I ever update the second object will the copy of that object be updated as well or do I need to simultaneously update all copies of said object.
For example:
public class Object()
{
int x = xValue;
Object linked = saidObject;
}
public class doStuff()
{
saidObject.x++;
if(linked.equals(saidObject))
return true;
}
will this code (not compilable obviously just fill in blanks) return true?
if(linked.equals(saidObject)) will return true as the two variables do point to the same object.
In Java all variables and fields are references to an actual Object that lives somewhere in memory.
When you assign one variable to another, it's like copying the address of the object so that they both point to the same object in memory.
e.g.
Object a = new Object(); // this actually creates the Object in memory
Object b = a; // this copies the reference to Object from a to b
// At this point, a and b point to exactly the same object in memory. Therefore ...
a.equals(b); // returns true.
In fact a == b returns true too, which is a better way of comparing for this case as == compares if two variables point to the same object (they do), whereas equals() often compares by value, which is unnecessary here.
It doesn't matter if b is actually a field within a (e.g. class Obj { Obj b; }; Obj a = new Obj(); a.b = a;) and it points to the same type of object, the principle is the same: a = b means they point to same object, nothing new is created.
By doing:
Object linked = saidObject;
you are not copying the object, just creating another pointer to it, it means you have two different pointers that point to the same object.
copying or cloning an object can be useful in some cases but its not the usual case.
An object instance is itself and is distinct from every other instance.
That is, mutating an object (by reassigning a field) someplace modifies it everywhere .. as, well, it is what it is. Likewise, mutating a different object .. is, well, changing a different object.
Related
I am currently in the process of obtaining my Oracle certification and this is one of the concepts that I am failing to grasp. The following code snippet does not print true even though I expect it to:
interface I {
}
class A implements I{
}
class B extends A{
}
class C extends B{
}
public class Test {
public static void main(String... args) {
A a = new C();
B b =(B)a;
C c =(C)a;
a = null;
System.out.println(b==null);
}
}
Why do I expect a true? b was created using a and a has now been set to null.
b was created using a and a has now been set to null.
You've misunderstood what this line does:
B b =(B)a;
That copies the current value of a as the initial value of b. That's all it does. The two variables are then entirely independent. Changing the value of a does not change the value of b. Yes, while they happen to refer to the same object, any changes to that object will be visible via either variable, but the variables themselves are not tied together.
One thing that may be confusing you is what the value of the variable is - it's just a reference. See this answer for the difference between variables, references and objects.
It is very normal that it will print false because b has been already initilized with the reference of the object a, even if they reset the a to null after that but b will keep always the reference of the object
When you create an object in Java using new, it is allocating space in memory for it and sets your a to the point in memory where your object is located.
a is not the object itself, it is a pointer to the location of your object in memory
A a = new C();
// a points to the location of your new C
B b =(B)a;
// now b also points to that location
C c =(C)a;
// same goes for c
a = null;
// a now points to null, but b and c still point to the old location
Think of it almost like int types. If you assign one int to another int, these two variables aren't "linked" -- instead the actual value is being copied (in the case of pointers / references: the location of the object in memory) from one to another
An abstract taken from Herbert Schildt book on Java
Cloning is a potentially dangerous action, because it can
cause unintended side effects. For example, if the object
being cloned contains a reference variable called obRef,
then when the clone is made, obRef in the clone will refer
to the same object as does obRef in the original.
If the clone makes a change to the contents of the object
referred to by obRef, then it will be changed for the original object, too.
So when the object is being cloned, do the references pointing to that
original object also gets cloned and as such these points to to the cloned object?
I am confused at this line "...obRef in the clone will refer
to the same object as does obRef in the original...".
Consider the difference between references to the original object, and references within the original object.
Suppose you have an object myObj of type MyClass which contains a field of type ArrayList named myList.
When you constructed this object, myList was initialized with new ArrayList() and is now pointing to an object in the VM's heap.
Now suppose you clone myObj
MyClass myClone = myObj.clone();
The variable myClone is pointing to a different object than myObj. They are two distinct objects. However, the myList field inside of myObj is pointing to the same object in the heap as myList in myClone. This is because when you clone, the references are copied as-is, there is no new ArrayList() that assigns a separate object to myList in the new object.
No references are ever changed automatically, so any references to your old myObj still point to it. The only reference you have to the new object is myClone until you assign it to additional variables. But the same is true for myList. So the two objects point to the same ArrayList. So if one of them adds to it, the other one sees the added values.
Normally, that's not what you need.
Lets say, I have a class called Another as shown :
public class Another {
int number;
String message;
// And so on.
}
And another class called CloneMe overriding clone() method ,as shown :
public class CloneMe {
int version;
Another another;
public CloneMe(int newVersion, Another obj) {
this.version = newVersion;
this.another = obj;
}
// and so on
#Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // You can also provide your own implementation here
}
}
Now, when you create an object of class CloneMe :
CloneMe actualObject = new CloneMe(10, new Another());
Then an instance of class Another is created and is assigned to reference another in your CloneMe class.
Now, when you call :
CloneMe clonedObject = actualObject.clone();
Then only a new instance of CloneMe is created with existing state of the actualObject. However, no new instance of any other class (for example, Another in our case) is created but the same object reference is assigned to the reference variable in the clonedObject. This is called shallow cloning.
I have come across two scenarios.
One in which an array is passed as argument to a method and if it is updated in the called method, it is reflecting in the calling method as well.
But in the second scenario, a String Object is passed as argument. The object is updated in the called method, but it doesn't reflect in the calling method.
I want to understand what is the difference between two, even though in both cases, value (of reference) is passed as argument. Please see below snippets.
Scenario 1:
class Test {
public static void main(String[] args){
int a[] = {3,4,5};
changeValue(a);
System.out.println("Value at Index 1 is "+a[1]);
}
public static void changeValue(int b[]){
b[1] = 9;
}
}
Output:
Value at Index 1 is 9
Here, reference (Memory Address) related to array a is passed to changeValue. Hence, b is just pointing to same address as a does.
Hence, whether I say b[1] or a[1], it is referring to same memory address.
Scenario 2:
public class Test {
public static void main(String[] args){
String value = "abc";
changeValue(value);
System.out.println(value);
}
public static void changeValue(String a){
a = "xyz";
}
}
Output:
abc
If I apply the same logic here, String Object VALUE's reference (Memory Address) is being passed to changeValue, which is recieved by a.
Hence, now a should be referring to the same memory location as VALUE does. Therefore, when a="xyz" is executed, it should replace "abc" with "xyz".
Can someone please point out where my understanding goes wrong? Thanks in advance!!
Java passes all its arguments by value. This means that a copy of the pointer to the String is made, and then passed to the method. The method then makes the pointer point at another object, but the original pointer still points to the same String.
This is not the same thing:
in the first example, you pass an array reference as an argument, therefore you correctly expect it to be changed by manipulating the reference directly;
in the second example however, you pass an object reference, sure -- but you change the reference itself in the method. Changes to a are not reflected when the method returns.
Consider any object:
public void changeObj(Object o)
{
o = new Whatever();
}
a new object is created, but it won't change o in the caller. The same happens here.
You're doing different things; with the string you set the parameter value, with the array you set something belonging to the reference.
For an equivalent array example you'd need to try setting the array reference to a new array:
public static void changeValue(int[] b) {
b = new int[] { 42, 60 };
}
The original array won't be changed.
The difference here is simple, and it is not actually about immutability of strings, as some other answers (now edited or deleted) might have originally implied. In one version (with the string), you have reassigned the reference, and in other version (with the array), you haven't.
array[0] = foo; // sets an element, no reassignment to variable
array = new int[] { 1,2,3 }; // assigns new array
obj = "hey"; // assigns new value
When you reassign the variable, you are not going to observe that change outside of the method. When you change elements of an array without reassigning the array variable, you will observe those changes. When you call a setter on an object without reassigning the actual variable of the object, you will observe those changes. When you overwrite the variable (new array, assigning new value, creating new object, etc.) those changes will go unobserved.
Arguments are passed (or copied) by value. The variable inside the method has the same value as the variable on the outside at the beginning. The variables are not linked, and they are not aliases for one another. They just happen to contain the same value. Once you reassign the value to one of them, that is no longer true! The variable on the outside is not affected by the variable on the inside, or even another local variable. Consider
Foo foo = new Foo();
Foo other = foo;
foo.setBar(1);
int bar = other.getBar(); // gets 1
foo = new Foo();
foo.setBar(42);
int bar2 = other.getBar(); // still gets 1
foo and other only referenced the same object for a time. Once foo was assigned a new object, the variables no longer had anything in common. The same is true for your reassignments to the parameter variable inside your method.
Thank you all for answers and updates..
I understood the difference between scenario 1 and 2 as below..
In scenario 1, the array reference is passed. The called method just updates one of the elements pointed by the reference.
While in scenario 2, the reference is passed, but when the called method assigns "xyz" to the reference variable (pointer), it actually creates a new String Object and its reference is assgined to a local reference variable 'a' (Pointer now points a different objct).
The code in called method is as good as
a = new String("xyz");
Hence, the object in called method and calling method are absolutely different and indepenedent and have no relation with each other.
The same could have happened with scenario 1, if instead of doing
b[1] = 9;
I would have used
b = new int[] {8,9,10};
I understood, Mutability fundamentals would have come in action, if I might have done like below..
String a="abc";
a="xyz";
In this case, object "abc" was being pointed by 'a'. When 'a' is assigned the duty to point to a new object "xyz", a new object "xyz" is created, which is not replacing the existing object "abc". i.e. "abc" is still existing but has no reference variable to keep itself accessible anymore. This non-replacement property is because of Immutability of String.
public static void main(String[] args) {
ArrayList a=null, b=null;
a=b;
a=new ArrayList();
System.out.println(a+""+b);
}
Why in the world b is printed as null ?
I thought java makes references the same then whatever you change in one of them reflects the other. But not in this case !!!
This line:
a = b;
Sets the value of a to the current value of b. That's all it does. The current value of b is null, so it's equivalent to:
a = null;
It does not associate the two variables. It just copies the value of one to another.
Changing the value of a afterwards does not change b at all. The two variables are entirely separate. Note that this is exactly the same for primitive types:
int a = 10;
int b = a;
a = 5;
System.out.println(b); // Prints 10, not 5
Even if you had:
ArrayList<String> a = new ArrayList<String>();
ArragList<String> b = a;
a.add("Hello");
System.out.println(b.get(0)); // Prints "Hello"
That's still not really showing a relationship between the variables a and b. They have the same value, so they refer to the same object (the ArrayList itself) - changes to that object can be observed via either variable. But changing the value of each variable to refer to a different list (or null) won't affect either the other variable or the object itself.
One thing which may be confusing you is what the value of a or b actually is. The value of a variable (or any other expression) in Java is never an object - it's always either a reference or a primitive value.
So an assignment operator, or passing an argument to a method, or anything like that will never copy the object - it will only ever copy the value of the expression (a reference or a primitive value).
Once you understand this, Java starts to make a lot more sense...
Variables like your a and b are called references. They refer to objects. The objects are floating around somewhere else (they are not stored "inside" the variables). When you say a=b you make a refer to whatever b refers to. In your case that makes no difference, because both already refer to null (i.e. to no object at all).
When you assign a new object to a that makes no difference to what b refers to.
Because you've redefined a. When you say:
a=new ArrayList();
You break the existing relationship between a and b.
Simply put. The variables refers to the object the other variable refers to in the moment it is set and not to the variable itself.
ArrayList a=null, b=null; // Both *a* and *b* refers to null
a=b; // Set *a* to refer to what *b* refers to (in this case null)
a=new ArrayList(); // Set *a* to refer to a new arraylist. *b* still refers to null.
I am doing the following statements in Java,
Obj t[] = new Obj[10];
Obj a = new Obj("a");
t[0] = a;
a = new Obj("b");
t[1] = a;
Why in java, when i access t[0] , it returns me "a", rather than "b"?
Is this because of the GC? and can i believe it is safe to do such an operation
Here's exactly what's happening.
Obj t[] = new Obj[10]; // 1
Obj a = new Obj("a"); // 2
t[0] = a;
a = new Obj("b"); // 3
t[1] = a; // 4
You create an array that can hold 10 references to instances of Obj. Call this obj01. You assign it to t. Note that the variable t and the actual object obj01 have a pretty casual relationship.
You create an instance of Obj, call this obj02. You assign a reference to this object to the variable a. Note that the variable a and the actual object obj02 have a pretty casual relationship.
You also put this reference into t[0]. You have one object known in two places. The object obj02 (with a value of "a") is known as a and known also as t[0].
You create an instance of Obj, call this obj03. You assign a reference to this new object to the old variable a. Note that the variable a and the actual object obj03 have a pretty casual relationship. a used to reference obj02, but it doesn't reference that anymore.
So, obj01 (an array) is referenced by t; obj02 (and instance of Obj) is known as t[0]; obj03 (an instance of Obj) is known as a.
You put the reference that's in a into t[1]. So, t[1] gets a reference to obj03.
At this point all the objects are referenced by variables which are in scope. Since all objects have references, they can't be garbage collected.
The problem is, Java doesn't have pointers.
When you assign one object variable to another, it changes what that variable points to but not any other references you might have.
So:
Object a = new Object("a");
Object b = new Object("b");
a = b;
b = new Object("c");
// At this point, a = "b"
// and b = "c"
As you can see, although you first set a = b, when you then set b to be a new Object, a still retains the reference to the old object.
The value in the array is just a reference. It's just like doing this:
Obj a = new Obj("a");
Obj t0 = a;
a = new Obj("b");
At the end, the t0 variable has the value it was given on line 2 - that is, a reference to the first Obj that's created on line 1. Changing the value of the a variable doesn't change the value of t0.
Once you understand the above, just think of an array as a collection of variables, e.g.
Obj[] t = new Obj[10];
is roughly like declaring:
Obj t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
(There are plenty of differences, but in the context of this question they're similar.)
When you do t[0] = a; you assign the address of object you created by new Object("a") in the array, whatever you re-use the a variable won't change the value contained in the array.
Why in java, when I access t[0] , it returns me "a", rather than "b"?
Because you told him to hold a reference to the object with "a".
Java don't manipulate directly the objects. Instead I uses has object references. But this reference hold the value of the reference ( not the reference ) So when you assign to t[0] the value of a, they both reference the same object.
Let's see if this pic explains it better:
alt text http://img520.imageshack.us/img520/8857/referencesq4.png
First, a and t[0] reference the same object.
Later a drop that reference but t[0] no.
At the end a and t1 reference the same object and t[0] remains unchanged.
Is this because of the GC?
No
and can i believe it is safe to do such an operation
Yes