I have a problem with ArrayList. I'm using ArrayList like this:
private ArrayList<Playlist> mPlaylists;
where Playlist is a class inherited from another ArrayList.
I do the following:
p = new Playlist(...some parameters...);
mPlaylists.add(p);
Later, when I use 'p' to get the index in the list:
int index = mPlaylists.indexOf(p);
an index of '1' is returned, even though inspection of the list clearly shows that it's index '4'.
Does anybody know why this fails?
Thanks.
B.R.
Morten
Edit:
Same problem without indexOf(), using equals():
private int GetIndex(Playlist playlist) {
for (int i = 0; i < mPlaylists.size(); i++) {
if (mPlaylists.get(i).equals(playlist)) {
return i;
}
}
return -1;
}
New edit:
This WORKS!:
private int getIndex(Playlist playlist) {
for (int i = 0; i < mPlaylists.size(); i++) {
if (mPlaylists.get(i) == playlist) {
return i;
}
}
return -1;
}
Solution:
As suggested, I changed the Playlist class to not enherit from ArrayList, but rather keeping an instance privately. It turned out that I only had to implement 4 ArrayList methods.
This does the trick; Now indexOf() returns the correct object!
Thanks to all contributors!
Most likely your PlayList messed up with the default ArrayList equals implementation, because the way indexOf is calculated to something like:
indexOf(Object o)
if( o == null ) then iterate until null is found and return that index
if( o != null ) iterate until o.equals( array[i] ) is found and return taht index
else return -1
end
So, you are doing something funny with your .equals method or your are accidentally inserting another element in the list when you think it is at the end.
EDIT
As per your edit... see? Your .equals() method is broken.
Consider doing a good review and make sure it adheres to the description defined in Object.equals
From the API:
int indexOf(Object o):
Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element. More formally, returns the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))), or -1 if there is no such index.
So the answer is that you need to override .equals() in Playlist.
There may be many reasons for this behavior:
1) If multiple elements in an ArrayList are equal (according to equals method), then the first one is returned. Maybe you simply have multiple identical objects.
2) Your PlayList class extends ArrayList (I am not sure it's a good idea). Therefore, if you didn't override the equals method, the comparison is based on the sequence of elements only. For example, any two empty PlayList instances will be considered equal.
3) If you DID override equals, check your implementation. It must return true for a comparison with the same reference, and in your case it doesn't.
I'm not sure why you are having this problem, but I think if I were you I would choose to use the newer Generic List to create your list like this:
List<Playlist> mPlaylists = new List<Playlist>();
p = new Playlist(<some parameters>);
mPlaylists.Add(p);
Related
I have below code and I have placed break points on overridden equals() and hashCode() methods of ContainerBean. When I run below application in debug mode, debugger stops at hashCode() only for System.out.println line and not while trying to remove element from List.
import java.util.ArrayList;
import java.util.List;
public class ListRemovalDriver {
public static void main(String[] args) {
List<ContainerBean> remitClaims = new ArrayList<>();
ContainedBean addedRemit1 = new ContainedBean();
addedRemit1.setRemitId(12345L);
ContainerBean added1 = new ContainerBean();
added1.setRemitBean(addedRemit1);
remitClaims.add(added1);
ContainedBean removedRemit1 = new ContainedBean ();
removedRemit1.setRemitId(12345L);
ContainerBean removed1 = new ContainerBean ();
removed1.setRemitBean(removedRemit1);
System.out.println("List before valid removal" + remitClaims);
remitClaims.remove(removed1);
System.out.println("List after valid removal" + remitClaims);
}
}
Am I missing something?
Would overridden equals() in ContainerBean not be called while removing element from list?
EDIT
I forgot to mention that hashCode() and equals() are working as expected i.e. elements getting removed as per equals() logic but its only debugger that is not taking me there on list remove function call.
Since you did not give the code I have to guess: You did not override equals, but instead added an overload like this:
public boolean equals(ContainerBean c) { ... }
This will not work because equals(Object) is called.
Change your equals implementation to take an argument of type Object and it will both get called and stopped at in eclipse debugger.
Would overridden equals() in ContainerBean not be called while
removing element from list ?
Yes, when you are using remove(Object o), then equals() in ContainerBean will be called to check the equality of the object and then remove it from the list as mentioned in the ArrayListAPI below (emphasis mine):
Removes the first occurrence of the specified element from this list,
if it is present. If the list does not contain the element, it is
unchanged. More formally, removes the element with the lowest index i
such that (o==null ? get(i)==null : o.equals(get(i))) (if such an
element exists). Returns true if this list contained the specified
element (or equivalently, if this list changed as a result of the
call).
But, on the other side, when you are removing an element using the index of the list (i.e., using remove(int index)), then there will NOT be any equals() check.
You can look here
Source code of ArrayList from jdk 7,
ArrayList.remove(Object o)
it invokes equals method to verify the object to remove from the collection
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
source: ArrayList Source
Alright, I'm new to Java, I'm just working through a class, and I've hit a bit of a snag on a program for class. I've managed to work my way through every bit of my final program, except for this last thing.
public static void remove(String studentID)
{
Integer foundLocation = 0;
for (int i = 0; i < studentList.size(); i++)
{
if (studentList.get(i).getStudentID().compareTo(studentID) == 0)
{
//This means we have found our entry and can delete it
foundLocation = i;
}
}
System.out.println(foundLocation);
if (foundLocation != 0)
{
System.out.println(studentList);
studentList.remove(foundLocation);
System.out.println(foundLocation.getClass().getName());
System.out.println("Student ID removed: " + studentID);
System.out.println(studentList);
}
else
{
System.out.println("Sorry, " + studentID + " not found.");
}
The code seems like it should work. But, what I get is that the remove doesn't actually do anything. My extra prints are there to verify. The ArrayList just plain doesn't change.
However, if I just replace:
studentList.remove(foundLocation);
with something like:
studentList.remove(3);
It just removes perfectly.
foundLocation is an Integer.
Can someone explain to me what I've got going on here?
I expect it's blindingly obvious to someone familiar with Java, but I'm missing it.
This is a bit of a nasty overload that snuck into the Collections API design.
There are two remove methods, one that you call with an int, and one that you call with an Object, and they do very different things.
Unfortunately for you Integer is also an Object, even though you want to use it as an int (and do that in a couple of other places, thanks to the magic of autoboxing that unfortunately does not work for remove).
remove(1) will remove by index (the 2nd element).
remove(Integer.valueOf(1)) will remove the object by its value (the first "1" found in the list).
It would have probably been wiser to give these two methods two different names.
In your case, change foundPosition to be an int.
ArrayList have two remove method,one is remove(int index) and the other is remove(Object object),
Your foundLocation type is Integer,when use it it will be a reference,so when you call remove(foundLocation) it will call remove(Object),trying to find a element == foundLocation,it can't find this so remove nothing,once you change the type to int,it will remove element at index foundLocation,refer the method doc.
There are two 'remove' methods in the ArrayList class. One accepts an Object type, the other accepts a int type. By using the Integer object, you are finding an element in the list that is equals to the Integer object. However when you remove by an int type, you are moving by the position of the element in the list.
studentList.remove(foundLocation) will result in the ArrayList checking for a Integer object that is equal to the one that is referenced by foundLocation. This is an object equality check. Two different Integer objects with the same value is deemed as being different even though they have the same numeric value.
studentList.remove(3) will result in the ArrayList to remove the fourth element in the list.
Assume that I know that the list SomeList contains thatObj. Does the following code remove reference to thatObj from SomeList or not?
SomeClass el = (SomeClass) thatObj.clone();
SomeList.remove(el);
Can't find through the reference if this method compares objects somehow. Intuition suggests that it should use Object.equals which returns true if references point to the same object, hence this code will not work.
If not then an additional question: how to remove from list if don't have the reference but know all the members of the object in question?
Can't find through the reference if this method compares objects somehow. Intuition suggests that it should use Object.equals which returns true if references point to the same object, hence this code will not work.
Yes, you are right.
If not then an additional question: how to remove from list if don't have the reference but know all the members of the object in question?
Two possibilities:
override the equals method in your class, create a new instance with all known members and call remove passing the newly created instance as a parameter
iterate through all the objects inside the list and remove the one that has the members equal to the values you have
remove method internally uses the equals method to check for the object in the list. If equal returns true then it will be removed. Overriding the equals method will allow to remove the objects properly. For your reference here is the code of ArrayList remove method:
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
Override the equals method on the class - here is the javadoc. Also look at Overriding the java equals() method quirk and Overriding equals and hashCode in Java.
Search the list to find the member by returning the index, then get the object and remove it. You can also remove it by the index. The code
SomeList.indexOf()
could help you to get the index of the object that override equals() and hashCode().
I want to retrive index of specific element of my list :
ArrayList<Field> list = new ArrayList<Field>();
list.addAll(profile.getFieldsList());
Object privacyName = "privacy";
int i = list.indexOf(privacyName);
boolean doesContain = list.contains(privacyName);
There is a field containing "privacy" in the list but i is always -1 and doesContain is always false. Why this search doesn't work ?
Why this search doesn't work ?
Because list contains instances of the Field class and you are calling the contains method passing a String instance.
To make it work you need to pass an instance of the Field class.
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
You need to override equals for logical equality or rely on default for reference equality.
In this case privacyName.equals(elementData[i]) is always false.
From the Java docs for indexOf:
Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element.
So your list does not contain the object privacyName;
In ArrayList Index of method will based on equals method. In field class overide equals and hasCode method of Object class. And you told that "There is a field containing "privacy" in the list" . IndexOf Array will based on equals method. As #rocketboy's ans, u need to overide equals as well as hasCode method properly.
Why do I need to override the equals and hashCode methods in Java?
I'm familiar with the ways I can get an element position in array, especially the ones showed here: Element position in array
But my problem is I can't figure out how to convert this code to fit my needs.
What I want to check is if a String has a match in an ArrayList and if so, what's the index of the String in the ArrayList.
The annoying part is I managed to verify the String is in the ArrayList (see first line of my code)
listPackages is the ArrayList
current_package is the String I want to find its position in listPackages.
Here's my code:
if (listPackages.contains(current_package)) {
int position = -1;
for(int j = 0; j < listPackages.size(); j++) {
if(listPackages[j] == current_package) {
position = j;
break;
}
}
}
Would appreciate any help!
Thanks!
Use indexOf:
int index = listPackages.indexOf(current_package);
Note that you shouldn't generally use == to compare strings - that will compare references, i.e. whether the two values are references to the same object, rather than to equal strings. Instead, you should call equals(). That's probably what was going wrong with your existing code, but obviously using indexOf is a lot simpler.
just use the call listPackages.indexOf(current_package);
ArrayList.contains(Object o) calls indexOf(Object o) internally in ArrayList:
/**
* Returns <tt>true</tt> if this list contains the specified element.
* More formally, returns <tt>true</tt> if and only if this list contains
* at least one element <tt>e</tt> such that
* <tt>(o==null ? e==null : o.equals(e))</tt>.
*
* #param o element whose presence in this list is to be tested
* #return <tt>true</tt> if this list contains the specified element
*/
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
Hope this will help you.change your code like this:
if (listPackages.contains(current_package)){
int position=listPackages.indexOf(current_package);
}
Also if you will make position variable as global you can access its value outside this block of code. :)
use the indexof method to get the position -
listPackages.indexOf(current_package)
http://download.oracle.com/javase/1.4.2/docs/api/java/util/ArrayList.html#indexOf(java.lang.Object)