When adding an object to a data structure the reference to the object is always added, not the object itself. So below code snippets are fundamentally the same ?
Snippet 1 -
Object objectRef = new Object();
Vector vector = new Vector();
vector.add(objectRef);
Object object = (Object)vector.get(0);
Snippet 2 -
Vector vector = new Vector();
vector.add(new Object());
Object object = (Object)vector.get(0);
Java always passes references by value. So whenever you use a reference as an argument to a function call, the reference value is copied. The object itself is not passed, a copy of its reference is. Its an important distinction to understand. It also is important to understand that with the reference you (or the library) can still operate on the object passed via its reference.
Your snippets are not entirely the same. In (1) you end up with two references to the same object, objectRef and object. In (2) you end up with only 1, object. In both cases the vector has a different reference to the object.
Both snippets are the same, the only difference is that you have a location variable named objectRef which can be modified after it was added to the vector, if it is modified, it will be reflected in the object returned from the vector as well since it IS the same object. Though the "Object" class doesn't exactly have any methods which can modify the object.
That's correct. In the java programming language there is only heap. Every object exists out there in magic heap land. Every non-primitive value is just a pointer whose only operation is to dereference. A List can be thought of as a list of pointers to strings, the actual data content of the strings is out on the heap, not inside the collection structure.
(This is the semantics of the language of course. Modern runtimes are under no obligation to actually do it that way, the JIT uses method stacks, it just has to behave exactly the same as if it worked that way.)
They result in the same state except that at the end of snippet 2, you don't have a symbol called objectRef.
Both snippets give the same results. The difference lies that in the first snippet you have three references to the same object (objectRef, object and a reference in vector), and in the second snippet you only have two references to the same object (object and a reference in vector).
Related
I'm working on some code and trying to figure out how to copy an object reference to another object. I keep seeing the clone() method used, but I've read it's flawed and the class I'm wanting to copy is already implementing serializable. So one question I have is about the difference between using '=' and the clone method - My understanding is that both of these are shallow copies so they should work the same, but if that's true, then what is the benefit of having a method for this?
The code I'm working on has 2 arrays of objects - both the same type of object, all objects in both arrays are initially null, and I assign the values of array B to equal array A.
As the code progresses objects in array A are initialized and values are assigned to the variables of the objects in array A.
At the end of the code though, all objects in array B are still null.
Do I have the concept wrong here?
If the concept isn't wrong I assume it's just something I'm overlooking in my code.
Any help is appreciated.
I'll make my comment an answer:
Your question is comparing apples to oranges, they are so completely different that they can't be compared. = assigns a reference, that's it. Clone creates a completely new object, one whose state should be the same as the cloned object, but again it is a completely different object/reference. As an aside, there are deep and shallow clones, and so the composite fields of shallow copied clones may be identical, but that's the subject of another question.
When you use =, you copy the reference of the object (in memory). When using .clone(), you create a new object.
How much is the overhead for the copy->modify->copy back method? Let's say I have an object that have a couple of methods and 5 pieces of 2 dimensional 1000*1000 arrays. Is it a good practice to copy an object like this to compute on every 10-100ms or not? I guess not, but my code would look 10 times neater.
Is there some secret technique to achieve this by no actual copying, just using some "different -short- name" for the object (instead of the original very long path)?
Java works by references, you will never obtain a copy of a non primitive type with the assignment operator, unless you are explicitly requesting a copy (by an instance method for example). Actually it works by value, on references: what is effectively assigned (and copied) is the reference on the heap to the object.
What I mean is that if you have
YourObject o = otherComplex.path.to.a.different.variable;
What's happening is that o is an alias to the other variable, they both refer to the same object on the heap so they both have same performance implications.
You don't neither need to assign it back, eg
YourObject o = otherComplex.path.to.a.different.variable;
o.method();
o.field = ...;
otherComplex.path.to.a.different.variable = o;
This is unnecessary as you are just reassigning values which are already equivalent.
I was recently looking into freeing up memory occupied by Java objects. While doing that I got confused about how objects are copied (shallow/deep) in Java and how to avoid accidently clearing/nullifying objects while they are still in use.
Consider following scenarios:
passing a ArrayList<Object> as an argument to a method.
passing a ArrayList<Object> to a runnable class to be processed by a thread.
putting a ArrayList<Object> into a HashMap.
Now in these case, if I call list = null; or list.clear();, what happens to the objects? In which case the objects are lost and in which cases only the reference is set to null?
I guess it has to do with shallow and deep copying of objects, but in which cases does shallow copying happens and in which case does deep copy happens in Java?
Firstly, you never set an object to null. That concept has no meaning. You can assign a value of null to a variable, but you need to distinguish between the concepts of "variable" and "object" very carefully. Once you do, your question will sort of answer itself :)
Now in terms of "shallow copy" vs "deep copy" - it's probably worth avoiding the term "shallow copy" here, as usually a shallow copy involves creating a new object, but just copying the fields of an existing object directly. A deep copy would take a copy of the objects referred to by those fields as well (for reference type fields). A simple assignment like this:
ArrayList<String> list1 = new ArrayList<String>();
ArrayList<String> list2 = list1;
... doesn't do either a shallow copy or a deep copy in that sense. It just copies the reference. After the code above, list1 and list2 are independent variables - they just happen to have the same values (references) at the moment. We could change the value of one of them, and it wouldn't affect the other:
list1 = null;
System.out.println(list2.size()); // Just prints 0
Now if instead of changing the variables, we make a change to the object that the variables' values refer to, that change will be visible via the other variable too:
list2.add("Foo");
System.out.println(list1.get(0)); // Prints Foo
So back to your original question - you never store actual objects in a map, list, array etc. You only ever store references. An object can only be garbage collected when there are no ways of "live" code reaching that object any more. So in this case:
List<String> list = new ArrayList<String>();
Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put("Foo", list);
list = null;
... the ArrayList object still can't be garbage collected, because the Map has an entry which refers to it.
To clear the variable
According to my knowledge,
If you are going to reuse the variable, then use
Object.clear();
If you are not going to reuse, then define
Object=null;
Note:
Compare to removeAll(), clear() is faster.
Please correct me, If I am wrong....
It depends on how many variables are referenciating to each of your objects, to explain this it would be better some code:
Object myAwesomeObject = new Object();
List<Object> myList = new ArrayList<Object>();
myList.add(myAwesomeObject);
myList = null; // Your object hasn't been claimed by the GC just yet, your variable "myAwesomeObject" is still refering to it
myAwesomeObject = null; // done, now your object is eligible for garbage collection.
So it doesn't depend whether you pass your ArrayList as an argument to a method or the like, it depends on how many variables are still refering to your objects.
If you passed an ArrayList to a method then list = null will have no effect if there is a live reference to the list somewhere eg in the calling code. If you call list.clear() anywhere in the code the references to the objects from this list will be nulled. Passing a reference to a method is not shallow copying it is passing reference by-value
Java GC automatically claims the objects when they are not referenced anywhere. So in most cases you will have to set the reference as null explicitly
As soon as the scope of the variable ends the object becomes eligible for GC and gets freed up if no other reference points to the object.
Java is pass by value so if you set the list as null in the method then it will not affect the original reference that was passed to you in the method.
public class A{
private List<Integer> list = new ArrayList<Integer>();
public static void main(String[] args) {
A a = new A();
B b = new B();
b.method(a.list);
System.out.println(a.list.size()); //Will print 0 and not throw NullPointerException
}
}
class B{
public void method(List<Integer> list){
list = null;
//just this reference is set to null and not the original one
//so list of A will not be GCed
}
}
If you put the list into a hash map, the hash map now holds a reference to the list.
If you pass the list as an argument to a method, the method will have a reference to it for the duration of the method.
If you pass it to a thread to be manipulated, the thread will have a reference to the object until it terminates.
In all of these cases, if you set list = null, the references will still be maintained, but they will disappear after these references disappear.
If you simply clear the list, the references will still be valid, but will now point to a list that has suddenly been emptied, by means that may be unknown to the programmer and may be considered a bug, especially if you use the thread.
I was recently looking into freeing up memory occupied by java objects.
A piece of advice.
It is usually a bad idea to think about this. And it is usually a worse idea to try to "help". In 99.8% of cases, the Java garbage collector is able to do a better job of collecting the garbage if you actually just let it get on with it ... and don't waste your effort by assigning null to things. Indeed, the chances are that the fields you are nulling are in objects that are about to become unreachable anyway. And in that case, the GC is not even going to look at the fields that you've nulled.
If you take this (pragmatic) view, all your thinking about shallow versus deep copies and when it is safe to null things is moot.
There is a tiny percentage of cases where it is advisable to assign null ... to avoid medium or long term storage leaks. And if you are in one of those rare situations where it is "recycling" objects is actually a good idea, then nulling is also advisable.
I tried setting my object2 in vector position 1 with a new object that has been modified by a copy constructor.
Generic object1 = new Generic();
//invoke the copy constructor of the Generic class
Generic object2 = new Generic(object1);
Vector<Generic> myVector = new Vector<Generic>();
myVector.add(object1);
myVector.add(object2);
this code works when I use it after I inputted data for object1, object2 gets the same data
object2= new Generic(object1);
myVector.setElementAt(object2, 1);
however, I thought the below code should be same as the above, but it does not give me the same data as object1 (just gets the default values of object1)
myVector.setElementAt(new Generic(object1), 1);
How come the second one doesn't work?
As Ted Hopp wrote in his comment, the two variants are identical except that the second variant does not assign a new value to object2.
I think you are not aware of the fact that references in Java are always copied (not the referenced object, but the reference itself): After calling myVector.add(object2);, your object2 and the second element in your vector are independent, apart from referencing the same object.
This means that if you change the object itself (e.g. calling object2.setValue("foo"); this affects both, object2 and the second element in your vector (as they are referencing to the same object). But if you set a other/new object as the second element of your vector, object2 still points to the old one, so object2 and the second element in your vector are totally independent.
I hope this helps :-)
As a side note: You should probably use List<Generic> myList = new ArrayList<Generic>();, unless you need the synchronization Vector provides.
I have encountered a problem in one of my Java projects, which causes bugs.
The problem sounds as following:
I have two arrays. Let's name them firstArray and secondArray. Object in this case is a seperate class created by me. It works, the array can be filled with objects of that type.
Object[] firstArray= new Object[];
Object[] secondArray = new Object[];
Now, when I get an element out of the first array, edit it and then copy it in the second array, the object from the first array gets altered too.
tempObj = firstArray[3];
tempObj.modifySomething();
secondArray[3] = tempObj;
Whenever I do this, the (in this case) 3rd element(actually 4th) of the first array gets the modifications. I don't want this. I want the first Array to remain intact, unmodified, and the objects I have extracted from the first array and then modified should be stored in the second so that the second array is actually the first array after some code has been run.
P.S. Even if I get the element from the first array with Array.get(Array, index) and then modify it, the element still gets modified in the first array.
Hopefully you understood what I wanted to say, and if so, please lend me a hand :)
Thank you!
You're going to have to create a new object.
The problem is the modifySomething call. When you do that, it alters the object on which it's called. So if you've only got one object (even by two names), you can't call modifySomething or they will both change.
When you say secondArray[3] = firstArray[3], you aren't creating a new object: you're just assigning a reference. Going through an intermediate temporary reference doesn't change that.
You'll need code that looks like this:
Object tempObj = firstArray[3].clone();
tempObj.modifySomething();
secondArray[3] = tempObj;
The clone() method must return a new object divorced from the original but having identical properties.
When you retrieve an element from your array, you have a reference to it. So if you modify it, the modification are shered through all the object's references.
In order to leave it intact, you should use some method like Object.clone() or create a new Object and use its constructor to initialize its fields.
The object extracted from the first array needs to be cloned to create a new instance that is seperate. Otherwise the modification will affect the object in the first array as it is the same object.
When you retrieve an element from your array, you get a reference to it. So if you modify it, the modification are shared through all the object's references.
In order to leave it intact, you should use some method like Object.clone() or create a new method which take in input your retrieved object and return a new one alike.
In Java, when you do this secondArray[3] = tempObj;, you actually put the reference to the array, not the real object
So firstArray[3] and secondArray[3] point to the same real object
What you need to do is to create a new object that is identical to your original object, and put the reference of the new object to your secondArray
It might worth to point out that default clone() function only does a shallow copy, so if you have mutable objects in your object's fields, it might cause some problems. Take a look at this article about how to do a deep copy