I got some problem with reference assignment in java.
Let me explain: in my code, i'm using an ArrayList of BooleanWrap (a home made class of boolean) which will be later assigned as a value in a HashMap (there is a for cycle which update the values of this ArrayList until a condition is verified).
Something like this:
ArrayList<BooleanWrap> temp=new ArrayList <BooleanWrap>(48);
//cycle: operations to fill the ArrayList, then a condition is satisfied
hashMap.put(index, temp);
After that, I have to reuse the temp variable, so I need to reinitialize it. I do it with the following instructions:
for(BooleanWrap bool: temp){
bool.set(false);
}
There comes my problem: assigning temp as a value of the hashMap will save only the reference of the variable, not the actual value.
So, reinitializing temp cause also the updating inside the hashmap (in this case, setting everything false).
Now, I think that even with clone() method I should get the same result (cause it produces a shallow copy of the ArrayList).
Is there a way to reuse the same variable temp in my cycle without assign later the reference of it to the hashmap?
Actually I can do it with a method which creates a deep copy of the arraylist:
public static ArrayList<BooleanWrap> deepcopy(ArrayList<BooleanWrap> original){
ArrayList<BooleanWrap> copy=new ArrayList<BooleanWrap>(48);
for(BooleanWrap bool: original)
copy.add(new BooleanWrap (bool.get()));
return copy;
}
but I need something done inline, without any other methods and as shorter as it can be.
Any advice/suggestion/insult?
The issue is not about variables. It is about objects and mutations upon them.
So create a new object as needed. The "issue" is that the original object stored in the HashMap is being mutated.
Avoiding re-use of variables, however, can (often does?) make code much more maintainable and understandable.
Happy coding.
After that, I have to reuse the temp variable, so I need to
reinitialize it. I do it with the following instructions:
for(BooleanWrap bool: temp)
{ bool.set(false); }
That does not re-initialize the temp variable. That re-initializes the contents of your temp variable. to re-initialize the temp variable your code would look like
ArrayList<BooleanWrap> temp=new ArrayList <BooleanWrap>(48);
//cycle: operations to fill the ArrayList, then a condition is satisfied
hashMap.put(index, temp);
//After that, I have to reuse the temp variable, so I need to reinitialize it.
// I do it with the following instructions:
temp = new ArrayList <BooleanWrap>(48);
//cycle: operations to fill the ArrayList
Using a BooleanWRap is very inefficient, even a Boolean would be inefficient.
Instead I suggest you use a BitSet.
BitSet temp = new BitSet(48);
//cycle: operations to fill the ArrayList, then a condition is satisfied
hashMap.put(index, temp);
// to create a new BitSet...
temp = new BitSet(48);
Related
I read that Java passes arrays to functions by reference (sort of) and it allows modification on it which would be reflected on the original array.
Well I'm not sure about the reference part in the above link because someone else said that Java is always pass by value, with no exceptions, ever. However I know for sure that modification on the argument array changes the original array too.
So does that mean that when I return the same array that was passed through arguments, Java would return a duplicate of the original array? and while not doing that and using the original array instead will save me some memory and CPU usage? or does Java duplicate the array in both cases?
For example are the following two functions identical or does the first one save memory and cpu resources?:
public void modifyArray (int[] arr)
{
for (int i = 0; i < arr.length; i++) arr[i] = i + 1;
}
public int[] modifyArray (int[] arr)
{
for (int i = 0; i < arr.length; i++) arr[i] = i + 1;
return arr;
}
Edit:
Just to be more clear, I am only concerned about the performance (especially when dealing with large arrays) and I don't actually need to copy the array, I have an existing code that does this and want to know if removing the retun part would improve performance.
Java passes the reference by value. Which means that replacing the array does no harm, i.e.
public void f(String[] a)
{
a = new String[42];
}
but changing anything in it will change the original array. Deep copying of general objects can be very time consuming and is also difficult in cases where objects contain objects which reference objects ... so that the standard behaviour is to avoid it.
Both functions modify the array that was passed in. What is passed by value is the pointer to the array, so when you operate on the underlying array that it points to, you are changing the array that was passed in. Thus, the second function is returning the same array that was passed in, after making some changes to it.
Now, if you put arr = ... somewhere in the function and then worked on it, you would not modify the array passed in, and what you return would be something different. This is why some say that Java is passing by value. It's just that the value is a pointer in all non-primitive cases.
The methods you've provided are identical in a way, that both modify the array that was passed as a parameter. There is no implicit deep copy when returning the array.
However, it's quite a good practice to either return the array/collection that is a deep copy or make it unmodifiable.
you can create the copy of the array by System.arraycopy which should be super fast, or, when using the containers, create an unmodifiable wrapper by Collections.unmodifiableList/Set/etc()
Note: this works only for "1D" of the container, if you have n dimensional array or container, you need to make the deep copy.
Every primitve is passed in Java by value.
Look at this example:
public void test2(int s) {
s = 2;
System.out.println(2);
}
If you ran it:
int k = 5;
reporter.test2(k);
System.out.println(k);
Java will pass s by value. It won't affect original value.
The output of k will be still 5.
In case of Objects - it's always reference by value. It passess reference to original value and modifies it.
Answring to your question - in second example you just return the reference to original array. Regardless of returning the reference or not - original one will be affected (because arrays are Objects).
You can do that; have a method return the same array that was passed as argument to that method.
But this makes the "interface" of that method a bit harder to understand.
In other words: unless we are talking really large arrays; or methods that are called hundreds of time per second; then you should focus on clear, readable code that doesn't surprise its readers; versus adding a return statement for no good reason.
You see, the caller of your method should know what he is doing. In other words: he is already passing some array to you; why do you think you should return that to him?
Problem with gui application where array of objects been passed to the constructor, however when new round is initialised, it modifies somehow const_AnimalFamily array, where I want to make it unchanged at each round, however final cannot be used here. Other class initialises this class, however here is my main. Any suggestions? Thank you!
why its been changed each time I modify animalFamily, const_AnimalFamily being affected even if I did not do anything to it?
Your code is much too large for being analyzed. But as you declared two arrays assigning their references to fields, I simply assume that you once assign one field to the other.
And indeed you have the line:
animalFamily = const_AnimalFamily;
I futher assume that you want to copy all contents from const_AnimalFamily to animalFamily. But this is not the case.
In Java, such assignments simply assign the reference to the variable (or the field). That means, both fields now refer to the same array. Actually, the array that was referred to by the field const_AnimalFamily before, is now obsolete and cannot be used anymore.
If you now access some array content, for example
animalFamily[0] = ...
and afterards read from
... = const_AnimalFamily[0]
you will get the same object that you previously wrote into the array.
Solution: If you really wanted to copy the array, do the following:
animalFamily = Arrays.copyOf(const_AnimalFamily, const_AnimalFamily.length);
Another (better) solution would be to use collections.
It's right as per your observation "Problem with gui application where array of objects been passed to the constructor, however when new round is initialised, it modifies somehow const_AnimalFamily array, where I want to make it unchanged at each round".
See this your code:
public AnimalGUI(Animal[] temp) {
System.out.println("INSIDE CONSTRUCTOR");
const_AnimalFamily = temp;
You are changing the reference of const_AnimalFamily to temp. So now whenever you modify temp (from wherever it was passed) you are going to go through same changes in your constant array.
I would suggest you do something like:
You do a deep copy of your temp array rather than changing the reference.
OR
when you pass temp array, you pass the cloned (Arrays.copyOf) version of array rather than raw array.
I have the following two Vector objects in java.
Vector<SomeClass> obj1;
Vector<SomeClass> obj2;
The class SomeClass has an int variable a.
Assume obj2 is empty and obj1 has some elements in it. Suppose I do this:
obj2.add(obj1.firstElement());
obj2.firstElement().a = 10; // obj2.firstElement() will be the object that was
//added above because obj2 was empty at first
Would this change the value of a in obj1.firstElement() too?
Basically I just want to know if these Vector operations are done by reference or value. My guess is that they are done by reference and this change will be reflected in obj1.firstElement() too.
You are right, the reference is copied (shallow copy) and so the change is reflected also in the original vector.
Although is was probably quicker to test this yourself in code then to post it here, you have guessed correctly
So I have an ArrayList in java. And what I'm doing is creating a new list with updated values. But I want to put those new values into the original ArrayList. This is important because I'm passing the original arraylist reference to an object that I no longer have access to, but I need to keep its contents up to date. Is there any way to make java copy the contents into a current reference? I hope that makes sense.
Also, I'd rather not clear the original arraylist and then loop through it pushing the new contents into it.
I need to do something like this:
ArrayList a;
ArrayList *b = a;
//pass b (the pointer) to something
ArrayList c;
*b = c;
I really hope I got that (pseudo) c++ code correct or I'll look pretty stupid =P
I can see how I'm not being clear, it's kind of complicated (this is in android so it's across a couple activities) so let me see if I can get my point across better.
Class1{
ArrayList a;
method1(){
a = Class2.getA();
method_that_uses_a(a);
}
}
Class2{
ArrayList getA(){
ArrayList a = new ArrayList
a = getDataFromWebsite();
return a;
}
Class1's method1() gets called periodically by another portion of code. But I need the reference to a stay the same, but the contents to change to the new contents.
I think your question is unclear, what do you mean by
"And what I'm doing is creating a new list with updated values. But I want to put those new values into the original ArrayList. This is important because I'm passing the original arraylist reference to an object that I no longer have access to, but I need to keep its contents up to date. Is there any way to make java copy the contents into a current reference? I hope that makes sense."
When you do
List a = new ArrayList
List b = a
you have one ArrayList object, and two references to the object, a and b.
Also note that there is an addAll method that you can use to add members of one collection to another collection. Note that I believe addAll does not do a deep copy, so if you use it both lists have copies of the same reference. So if list a has references a1, a2, a3, and you do b.addAll(a), b now has references to the objects that a1...a3 point to...
The array classes all expose public clone() methods, however, so if a
shallow copy of the array is sufficient then
return (ElementType[]) myArray.clone();
Makes for a nice, simple, easy to read paradigm. If "ElementType" is a
primitive type then there is no distinction between shallow and deep
copying, and if it is immutable then performing a deep copy would be
wasteful. In some other circumstances a shallow copy is what you would
want anyway (you want the receiver to be able to mutate the returned
array elements with effects visible to the host object).
If you find that you really do want to make a deep copy of the array
then you might want to consider whether your design can be improved; it
is not necessarily so, but I wouldn't be surprised.
In Java as I hope you;ve found out by now, all variables are references. Among other things this means that unless they are assigned to an object they don't 'point' at anything. You need to write:
ArrayList a = new ArrayList();
or a doesn't 'point to' an actual object - it's just null.
If you write:
ArrayList a = new ArrayList();
ArrayList b = a;
modify(b);
ArrayList c = b;
then there is only one ArrayList. All the variables a, b and c refer to it. Any modifications done in the 'modify' method apply to it, and will be reflect in the state of a, b and c.
You're C++ code says this:
ArrayList a; //make arraylist
ArrayList *b = a; //set b to point to same arraylist as a
//pass b somewhere
ArrayList c; //make arraylist
*b = c; //variable b in THIS PROGRAM now points to c. arraylist is unchanged.
You want to update the arraylist, not the pointer to it, as that pointer only 'exists' in the current context. The code you passed the arraylist to doesn't give a darn if a pointer back in who-knows-where now points to the same arraylist that its using. It's the actual object the other code cares about. To update that object, you can just call methods on it, like a.add(bar)
BUT there's more to it. If you call a function you don't control (now known as foo) and pass it an arraylist, that's all fine. But if you want to update it from the code calling foo, you run into issues. Imagine if an object you were working with could change randomly at any time. All sorts of bad stuff could happen. If you really need this capability (and we can help you judge if you do), look into the topic of threading.
I have a Vector that holds a number of objects. My code uses a loop to add objects to the Vector depending on certain conditions. My question is, when I add the object to the Vector, is the original object reference added to the vector or does the Vector make a new instance of the object and adds that?
For example, in the following code:
private Vector numbersToCalculate;
StringBuffer temp = new StringBuffer();
while(currentBuffer.length() > i) {
//Some other code
numbersToCalculate.add(temp);
temp.setLength(0); //resets the temp StringBuffer
}
What I'm doing is adding the "temp" StringBuffer to the numbersToCalculate Vector. Should I be creating a new StringBuffer within the loop and adding that or will this code work? Thanks for the help!
Eric
You need to create a new StringBuffer each time. Each item item in the Vector is just a pointer to the same StringBuffer object, so each time through the loop you are resetting the single instance of stringbuffer and adding the same reference to the Vector.
Just replace the temp.setLength(0); with temp = new StringBuffer();
If you have to have an independent object added to the Vector, create a new one each time.
You're adding references to the vector. If the state of an object changes, then all references to it see the change.
It uses the same object each time. You should add a temp = new StringBuffer(); to the end of your loop. (The result of your loop will be a Vector of pointers to the same single empty StringBuffer.)
The Vector will store the reference you give it, it won't create its own copy of the object. So if you want the Vector to have buffers separate from the one you're continuing to use, as you said you'll need to create those separately by creating a new buffer instead of setting the old one's length to zero.
Off-topic side note: Vector is fairly out of date. you're probably better off with ArrayList (or one of the other classes implementing List, if you don't need an array backing it).
Inserting an element into a collection does not, and can not, make a copy of an object, because Java has no formalized notion of a copy-constructor or operator overloading for user-defined types. That is, a general purpose collection can not know how to copy the contained objects.
Java's assignment operator always copies the pointer, never the contents, of a user-defined type.
As most of the answers here say, a Vector stores references to objects of type Object. If you change the underlying Object each time you will end up with a Vector containing lots of references to one object, which now contains the last value you gave it.
Based on the name of your variables, I'm guessing you actually want to be storing numbers in your Vector.
In an ideal world you would just add object of type int into the Vector. Unfortunately, in Java an int is a 'primitive type', and Vector can only store objects of type Object. This means you can only put Integer objects into the Vector instead of int objects.
So your code will look something like:
// Put a number at index 0
Integer inputNumber = new Integer(7);
numbersToCalculate.add(0, inputNumber);
// Some time later read out the value at index 0
Object objFromVector = numbersToCalculate.elementAt(0);
// Cast the Object to an Integer
Integer numberToProcess = (Integer)objFromVector;
This code will throw an IllegalCastException if the Vector contains something that isn't an Integer object. If you are worried about that you can encompass it in a try catch statement.
In your example you will presumably want to just loop through all the numbers in the Vector. You also might want to be more prescriptive about what objects your Vector can contain (called 'Generics', which is similar to C templating). Here's what it might look like:
Vector<Integer> myVector = new Vector<Integer>();
// Add stuff to the Vector
for (Integer number : myVector)
{
// Do stuff with the number
}
The foreach and Generics constructs were only added in Java SDK 1.5, so you can't use them if you want to run on an earlier Java SDK.