Почему Содержит () / indexOf () в коллекциях Java использование o.equals (e), а не e.equals (o)? - PullRequest
2 голосов
/ 27 мая 2010

Почему методы contains() и indexOf() в структуре коллекций Java определены с использованием o.equals(e), а не e.equals(o) (где o - аргумент методы и e является элементом в коллекции)?

Кто-нибудь знает причины этого?

Ответы [ 3 ]

16 голосов
/ 27 мая 2010

Потому что известно, что o не равно нулю, но e не обязательно. Возьмите этот пример из кода для LinkedList:

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

В этом примере, если вы сделаете это наоборот, вам не нужно будет защищать от того, что e.element будет нулевым для каждого элемента коллекции. Вот полный код, который учитывает, что o равен нулю:

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++;
    }
}
1 голос
/ 19 ноября 2012

Предположим, у вас есть коллекция дружественных объектов, например,

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) );

и вы хотите вставить недружелюбный объект, который никогда не будет найден в коллекции contains:

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

Если contains называется e.equals(o), тогда ваш зловещий план потерпит неудачу, поскольку дружественные элементы, уже находящиеся в коллекции, решат, равен ли объект недружественный им или нет , При вызове o.equals(e) это недружелюбный объект, переданный contains, который решает, чему он хочет быть равен, что позволяет вам использовать средство переопределения метода.

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? - это true, потому что мы используем ArrayList; если бы мы использовали HashSet или что-то еще хэшированное, становится необходимым также указать метод hashCode.

Обратите внимание, что хотя контракт на contains требует использования метода equals, некоторые реализации могут не соответствовать этому, например, org.eclipse.emf.common.util.BasicEList, тратя ваше время на то, чтобы вы это выяснили.

В этом случае вы должны сделать сравнение самостоятельно, например,

boolean contained = false;
for( Object e : c )
    if( o.equals(e) ) { contained = true; break; }
1 голос
/ 27 мая 2010

Разница между использованием x.equals(y) и y.equals(x) заключается в следующем:

Если x равно null, y.equals(x) просто вернет false, а x.equals(y) приведет к NullPointerException.

...