I have the following code in ThisClass:
static ArrayList<MyClass> classlist;
If I call:
ThisClass.classlist = new ArrayList<MyClass>();
ThisClass.classlist.add(object);
And then call this line again:
ThisClass.classlist = new ArrayList<MyClass>();
Will it reset the ThisClass.classlist list, i.e. the classlist list will no longer contain object?
Here's an illustration:
Code 1: Creating the ArrayList and Adding an Object
ThisClass.classlist = new ArrayList<MyClass>();
ThisClass.classlist.add(object);
Results into this:
Code 2: Resetting through Re-initialization
ThisClass.classlist = new ArrayList<MyClass>();
Results into this - you're resetting it by making it point to a fresh object:
Code 3: Resetting by clearing the objects
What you should do to make it "no longer contain an object" is:
ThisClass.classlist.clear();
Clear loops through all elements and makes them null. Well internally the ArrayList also points to the memory address of its objects, but for simplicity, just think that they're being "deleted" when you call this method.
Code 4: Resetting the entire classlist
If you want to make it "no longer contain an ArrayList" you do:
ThisClass.classlist = null;
Which means this:
Also, take note that your question's title mentions "static ArrayList". static doesn't matter in this context. The result of your problem will be the same whether the object is static or not.
Calling
ThisClass.classlist = new ArrayList<MyClass>();
does will clear the ThisClass.classlist array (actually, will create a new ArrayList and place it where the old one was).
That being said, it is much better to use:
ThisClass.classlist.clear();
It is a way clearer approach: shows your true intention in the code, indicating what you are really trying to accomplish, thus making you code more readable/maintainable.
Correct.
Technically, you do not clear the ArrayList doing so, you actually instantiate a new empty ArrayList.
Related
I keep getting a NullPointerException when I try to access elements of an array I created and don't know why. The code that throws:
TreeNode[] list1;
list1 = new TreeNode[1000];
list1[0].edges = new EdgeNode(1); //Throw line
but if I do this, it works:
TreeNode[] list1;
list1 = new TreeNode[1000];
list1[0] = new TreeNode();
list1[0].edges = new EdgeNode(1);
and I don't know why. Obviously I could for loop through the whole array and make new elements but doesn't that defeat the point of new? Also, if relevant, I have defined the default constructor for TreeNode.
You actually answered your own question: elements of an array should be individually initialized. By default they are null for array of objects. Hence NullPointerException.
This is exactly how java works. When you create an array, all elements are initialized to null, and you need to initialize them. That is because there is no way it could find out whether you just wanted them constructed with the default constructor, or with a different constructor with constant parameters, or a different constructor with varying parameters, or null, or what. So it just initializes the array to null.
After you say list1 = new TreeNode[1000],
list1 is a new array full of nulls.
So you have to loop through and initialise it
It does not defeat the point of new, because when you say new A[10000], that is allocating a new array, not its' elements. Saying list1[0] = new TreeNode(); allocates an element.
I agree this isn't elegant but that is java for you. :)
When you call new TreeNode[1000] you are instantiating an array of references, not the objects themselves. This is normal since the compiler can't just assume which constructor to call. Imagine if you had a class that didn't have a no-argument constructor: how do you think the compiler would have to instantiate it in that case?
There are two Initialization involved in this scenario
Initialization of the Array
Initialization of Array Elements
new TreeNode[1000] only initializes Array not Array Elements.
list1 = new TreeNode[1000];
This is only creating a new TreeNode array. The array itself is an object. So don't let the new keyword fool you. So with the above code, all you have is an array of TreeNode type. That only holds values of a TreeNode type. Does not give it any TreetNode` value. You must do that explicity yourself with code.
When you create new array of objects it is by default filled with nulls so when you are executing
list1[0].edges
in reality you are trying to execute
null.edges
which is incorrect since null doesn't have edges.
There are few reasons why arrays are not filled with new objects after being created:
In many (if not most) cases we want to place in array objects that already exists, so creating new ones would be waste of time.
Which constructor should compiler use to create objects that would fill array?
What arguments should be used in such constructor?
Remember that array can be array of classes that can't be instantiated like abstract classes or interfaces. How would compiler fill such array? Which subclass should be used?
I have an object stored in a global variable let's say:
static ArrayList<Object> list = new ArrayList<Object>();
I want to store it later to look into it without actually changing the values in the structure itself. So I am doing something similar to this:
public void someMethod()
{
ArrayList<Object> tempList = new ArrayList<Object>();
tempList = list;
list.remove(0);
}
I'm thinking this may have something to do with me initializing the variable as "static". I don't usually do that but Eclipse told me I had to so I just let the change happen.
My understanding would be that I am storing the original list into a temporary list and anything I do to the temporary list would be independent of the original list. But it appears that if I were to remove something from this above list, that the original list is removing it as well.
I remember learning that this could happen sometimes but I think I've done this before without having that issue.
I apologize if this is a repeated question but the way I worded it didn't show me an question that was similar.
Thanks!
My understanding would be that I am storing the original list into a temporary list and anything I do to the temporary list would be independent of the original list.
This is not the case. When you do something like
a = b;
then both a and b refer to the same object. Mutations in a show up in b and vice verse (since there is only a single object in question). In this case you probably want to use the copy constructor of ArrayList:
ArrayList<Object> tempList = new ArrayList<Object>(list);
Notice that here we are explicitly creating a new, independent object and assigning that to tempList.
Note that this creates what's called a shallow copy: the objects referenced by the list themselves are not copied, but instead a new list is created that contains the references to the same objects as the original list.
At the end of your someMethod, your tempList disappears into the dark void of the GC. If you want to keep it, you need to turn it into a similar field as list is.
Also, assigning list to tempList makes you have two references to the same object.
Lets say I have a list like this:
private LinkedList<String> messages = new LinkedList<String>();
When my method gets invoked for the first time there some strings added to this list. And I have also another method in which I need to clear this list from previously added values. To clear it I can use:
messages.clear();
This will remove all the elements from the list. Also I can create a new instance like this:
messages = new LinkedList<String>();
Which way is more proper to clear the list?
messages.clear();
Will actually clear the list, messages = new LinkedList<String>(); will just set messages as referencing a new list instance, so you could argue the first way is more "correct" to clear the list instance.
Say you have a list that is referenced by two variables, a and b. Like this (they don't have to be as close to eachother as this, they might even be in different files..):
final List<String> a = new LinkedList<String>();
final List<String> b = a;
Now, there is a big difference between
a.clear();
which will make both a and b reference the same, empty list, and
a = new LinkedList<String>();
which will make 'a' reference a new, empty list, and 'b' the old, populated list. (So they do not reference the same list).
Since you probably want them to reference the same list, a.clear() is preferred, since you won't get any surprises when your looking at the list referenced by b (which you might believe to be empty, but turns out to be populated if you use the new-approach).
I prefer the first approach i.e. messages.clear(); as it clear the elements but the List is not destroyed and recreated. All elements are removed as desired.
One side effect is there though: It iterates your list and removes one item at a time so if the list is huge then it's an unnecessary overhead.
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
Same way second approach has also one side effect: If you are using the object reference of you r list somewhere else in your program, that needs to handled properly otherwise you could get some unwanted surprises e.g. if you added your list to some other object/variable, then first approach will clear that elements from every place where it was referenced while second will not.
Summary: Both the approach outcomes are different in low level nature; though they seem to to serve your high level requirement (clearing the list). Decide carefully based on your low level requirements.
They are almost similar, but I would say messages.clear() is more flexible.
The second approach is simple and much used, but the problem where you have final modifier on your list you can not clear it that way.
messages.clear();
is more efficient. For more safety you can ask if this list is not empty befor
Personnaly I prefere to use LinkedList#clear because it is more clearly to understand during reading the code what you are doing.
But the new LinkedList<String>(); will work fine as well. So it's up to you what to use!
It clearly depends upon your need.
If you want to keep reference to your list object instance (as an example if that clear method is called inside a method in which the messages is a parameter, then the call to .clear() is the best solution.
On the other hand, if the list you want to clear is a member field (or a local variable in a method) of the object the current method is a member of, then you can call new LinkedList<String>(); without any trouble.
Notice that, to avoid the first (which I tend to disapprove), i usuall always return obejcts I modify as results from methods modifying them.
the first one is preferable. the second one makes some extra burden on the garbage collector. but the first one not.
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
I was looking through Java code, and I came across this code:
list = new ArrayList();
uselist(list);
if (condition)
list = new ArrayList();
What's the use of this, as opposed to simply using the clear() method of ArrayLists.
is using the new command to clear a list is ok and is it faster than clearing a list ?
i am using java version 1.6
Do note that clearing and re-instantiating a list is not the same thing!
Consider this example:
a = new ArrayList();
a.add("Hello")
b = a;
a = new ArrayList(); // a is now empty while b contains hello!
Versus
a = new ArrayList();
a.add("Hello")
b = a;
a.clear(); // Both a and b are now empty.
If the side-effects (shared references) are not an issue, then it is just two ways of clearing a list. It should probably not be a performance issue unless this is called millions of times.
No, they don't do the same thing. The method clear() clears an existing list - anything which still has a reference to the list and looks at it later will see that it's empty.
The approach with the new keyword, changes the value of the list variable but does nothing to the existing ArrayList object - so if anything else has a reference to the same object, they won't see any changes.
If the list is used elsewhere calling clear() might cause side effects.
However, if that is not the case, I'd say that creating a new list instead of clearing the old one might be faster (however, probably for huge lists only, since ArrayList's clear() just iterates over the elements and set's them as null), but most likely it's just a matter of programming style.
Wether it is the same or not it depends on what uselist(...) does internally with the list.
For example, suppose you have the following code in uselist :
public void uselist(List l) {
this.mylist = l;
}
In that case, your code will create a new list and not touch this.mylist . If instead you call .clear() on it, you are clearing that same list.
The difference can be fatal and hard to see. For example hibernate will flip out of you use list = new ArrayList(); and then try to update the list in the db but it works just fine with clear() as hibernate then can see the connection.
clear() // operates on your old object
list = new ArrayList(); // list will be a new object the old will be GCed