views:

115

answers:

4

Hi Experts, 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!

A: 

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);
Russ Clark
Can't instantiate a List .. couldn't down vote though, out of votes today ;-)
Lauri Lehtinen
The OP is using the generic form - just not the List interface, but the implementation ArrayList. While not totally clean, this usually considered ok as a private member of a class. When you wrote simply won't compile - you cannot instantiate a List - it is an interface. Put 'ArrayList' on the right hand side of the assignment and it'll be ok.
mdma
@Lauri - never fear, I have votes left >:-) Russ - this won't even compile, and doesn't answer the question.
Andrzej Doyle
+4  A: 

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

OscarRyz
+1: Beat me to it by a minute
Andrzej Doyle
As per your new edit, you're doing references comparission which makes me think you are not really inheriting ArrayList at all. Looks like your are doing something really strange with that `PlayList` class ( like using uppercase method names yiack... )
OscarRyz
Hehe, yes - but at least by using uppercase method name, I will not forget that this is only a test method, for the purpose of tracking down this problem :-)Thanks!
Morten Priess
I guess reference comparison works in this case because it's simple. I still can't see what I could have done with the class to upset equals()?
Morten Priess
jejej... you will, believe me.. you will... :) What about using underscore like `_add()` or `_getIndex()` Or even better, preppending "test" to the method....
OscarRyz
@Morten: Me neither, If you really inherit `ArrayList` not overriding .equals would be enough because it is already don. Try this, if you have a .equals method rename it to... .myEquals... to let the default ( ArrayList ) implementation work and see if that helps
OscarRyz
+1  A: 

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.

Dave
He should not if he is really inheriting `ArrayList` because that method is already overridden for that class. So, the suggestion would be **not** to override it again ( or doing it properly )
OscarRyz
Hmm... So what I did; Inherit from ArrayList and not overriding equals() should work? ...
Morten Priess
A: 

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.

Eyal Schneider
I can see your point, but as I didn't override equals(), and there are some String members furter down which differ, I still wouldn't expect them to come up as 'equal'?
Morten Priess
@Morten Priess: What was the type of elements inside the PlayList? What was the equals() implementation for this type? If PlayList simply contains String objects, then I can't explain this behavior.
Eyal Schneider