开发者

Why do contains()/indexOf() in Java collections use o.equals(e) and not e.equals(o)?

Why are the methods contains() and indexOf() in the Java collections framework defined using o.equals(e) an开发者_如何学God not e.equals(o) (where o is the argument of the methods and e is the element in the collection)?

Anyone know the reasons of that?


Because o is known not be null, but e isn't necessarily. Take this example from the code for LinkedList:

for (Entry e = header.next; e != header; e = e.next) {
    if (o.equals(e.element))
        return index;
    index++;
}

In this example, doing it this way round avoids the need to protect against e.element being null for every item in the collection. Here's the full code that takes account of o being null:

if (o == null) {
    for (Entry e = header.next; e != header; e = e.next) {
        if (e.element == null)
            return index;
        index++;
    }
} else {
    for (Entry e = header.next; e != header; e = e.next) {
        if (o.equals(e.element))
            return index;
        index++;
    }
}


The difference between using x.equals(y) and y.equals(x) is the following:

If x is null, y.equals(x) would simply return false whyle x.equals(y) would result in a NullPointerException.


Assume you have a collection of friendly objects, e.g.

class Friendly {
    final int i;
    Friendly( int i ) { this.i = i; }
    public boolean equals( Object o ) {
        return o != null && o instanceof Friendly && ((Friendly)o).i == this.i;
    }
}

java.util.Collection c = new java.util.ArrayList();
for( int i = 0; i < 10; i++ )
    c.add( new Friendly(i) );

and you want to insert an unfriendly object, which is never to be found in a collection by contains:

class Unfriendly extends Friendly {
    Unfriendly( int i ) { super(i); }
    public boolean equals( Object o ) { return false; }
}

If contains called e.equals(o) then your sinister plan would fail, as the friendly elements already in the collection get to decide whether an unfriendly object equals to them or not. By calling o.equals(e) it is the unfriendly object passed to contains which gets to decide what it wants to be equal to, allowing you to make use of the method overriding facility.

System.out.println("contains friendly? " + c.contains(new Friendly(1)));
#> contains friendly? true
System.out.println("contains unfriendly? " + c.contains(new Unfriendly(1)));
#> contains unfriendly? false

contains friendly? is true because we are using ArrayList; had we been using HashSet or anything hashed, it becomes necessary to specify a hashCode method too.

Notice that although the contract for contains requires the use of the equals method, some implementations may not conform to this, such as org.eclipse.emf.common.util.BasicEList, wasting your time by having you figure that out.

In this case you have to do the comparison yourself, e.g.

boolean contained = false;
for( Object e : c )
    if( o.equals(e) ) { contained = true; break; }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜