Як метод ArrayList's містить () оцінює об'єкти?


303

Скажіть, я створюю один об’єкт і додаю його до свого ArrayList. Якщо я тоді створять інший об’єкт із точно таким же входом конструктора, чи contains()метод оцінить два об'єкти однаковими? Припустимо, конструктор не робить нічого смішного з введенням, і змінні, що зберігаються в обох об'єктах, однакові.

ArrayList<Thing> basket = new ArrayList<Thing>();  
Thing thing = new Thing(100);  
basket.add(thing);  
Thing another = new Thing(100);  
basket.contains(another); // true or false?

class Thing {  
    public int value;  

    public Thing (int x) {
        value = x;
    }

    equals (Thing x) {
        if (x.value == value) return true;
        return false;
    }
}

Це як classслід реалізувати, щоб мати contains()прибуток true?

Відповіді:


339

ArrayList implementsсписок інтерфейсів.

Якщо ви подивіться на Javadoc дляList в containsметоді ви побачите , що він використовує equals()метод оцінки , якщо два об'єкти є однаковими.


61
На випадок, якщо ви плануєте перевизначити рівний (), переконайтесь, що ви також замініть метод хеш-коду (). Якщо ви не хочете, під час використання колекцій речі можуть не працювати так, як очікувалося?
Мохд Фарид

34
Це правильна відповідь, але зауважте, що вам потрібно змінити метод рівнянь, щоб прийняти, Objectа не а Thing. Якщо цього не зробити, ваш метод рівних не буде використовуватися. :)
mdierker

1
Щойно я виявив для себе, що затемнення має "Створити хеш-код () і дорівнює" в меню Джерело.
Володимир Крупач

Це відповідає на питання в заголовку, але не на запитання в описі, тобто "Якщо я тоді створять інший об'єкт із точно таким же введенням конструктора, чи метод" (") оцінить два об'єкти однаковими?"
robguinness

3
Collectionsроблять свої речі оптимізованим способом, тобто contains()спочатку перевіряють hashCodes двох об'єктів, а вже потім дзвонять equals(). Якщо hashCodes відрізняються (що завжди має місце для двох різних примірників Thing), equals()метод не буде викликаний. Як правило, коли ви перекриваєте equals(), не слід забувати і про перебір hashCode().
Севастьян Саванюк

52

Я думаю, що правильні реалізації повинні бути

public class Thing
{
    public int value;  

    public Thing (int x)
    {
        this.value = x;
    }

    @Override
    public boolean equals(Object object)
    {
        boolean sameSame = false;

        if (object != null && object instanceof Thing)
        {
            sameSame = this.value == ((Thing) object).value;
        }

        return sameSame;
    }
}

1
ifзаява непотрібна. instanceofдостатньо.
Пол

@Paul, про яку частину заяви ви говорите?
ChristopheCVB

4
Ця object != nullумова непотрібна, тому що object instanceof Thingперевірки на предмет також не є нульовими.
Олександр Фарбер

15

ArrayList використовує метод equals, що реалізується в класі (ваш клас Thing class) для порівняння рівних.


12

Як правило, ви також повинні переосмислювати hashCode()кожен раз, коли ви переобираєтесь equals(), навіть якщо тільки для підвищення продуктивності. HashCode()вирішує, у яке відро сортирується ваш об’єкт, коли проводиться порівняння, тому будь-які два об’єкти, які equal()оцінюються як істинні, повинні повертати те саме hashCode value(). Я не можу пригадати поведінку за замовчуванням hashCode()(якщо він повертає 0, то ваш код повинен працювати, але повільно, але якщо він повертає адресу, то ваш код вийде з ладу). Я пам’ятаю безліч разів, коли мій код вийшов з ладу, тому що я забув переотримати hashCode(). :)


7

Він використовує метод рівних на об'єктах. Отже, якщо Thing перевизначення не дорівнює і не використовує для порівняння змінні, що зберігаються в об'єктах, воно не поверне істину в contains()методі.


6
class Thing {  
    public int value;  

    public Thing (int x) {
        value = x;
    }

    equals (Thing x) {
        if (x.value == value) return true;
        return false;
    }
}

Ви повинні написати:

class Thing {  
    public int value;  

    public Thing (int x) {
        value = x;
    }

    public boolean equals (Object o) {
    Thing x = (Thing) o;
        if (x.value == value) return true;
        return false;
    }
}

Зараз це працює;)


6
ви не повинні робити Thing x = (Thing) o; без попередньої перевірки, чи інший об’єкт недійсний
steelshark

5

Просто хотів зазначити, що наступна реалізація помилкова, коли valueце не примітивний тип:

public class Thing
{
    public Object value;  

    public Thing (Object x)
    {
        this.value = x;
    }

    @Override
    public boolean equals(Object object)
    {
        boolean sameSame = false;

        if (object != null && object instanceof Thing)
        {
            sameSame = this.value == ((Thing) object).value;
        }

        return sameSame;
    }
}

У цьому випадку я пропоную наступне:

public class Thing {
    public Object value;  

    public Thing (Object x) {
        value = x;
    }

    @Override
    public boolean equals(Object object) {

        if (object != null && object instanceof Thing) {
            Thing thing = (Thing) object;
            if (value == null) {
                return (thing.value == null);
            }
            else {
                return value.equals(thing.value);
            }
        }

        return false;
    }
}

як це здійснити, усуваючи дублікат?
Суджай

4

Інші плакати вирішили питання про те, як містить () твори.

Не менш важливим аспектом вашого питання є те, як правильно реалізувати рівняння (). І відповідь на це дійсно залежить від того, що являє собою об’єктну рівність для цього конкретного класу. У наведеному прикладі, якщо у вас є два різних об'єкти, у яких обоє мають х = 5, чи вони рівні? Це дійсно залежить від того, що ви намагаєтеся зробити.

Якщо вас цікавить лише рівність об’єктів, тоді реалізація .equals () (за умови, що надається Object) за замовчуванням використовує лише ідентичність (тобто це == інше). Якщо це те, що ви хочете, тоді просто не реалізуйте рівняння () на своєму класі (нехай він успадковується від Object). Код, який ви написали, хоч на зразок правильного, якщо ви збираєтесь посвідчити особу, ніколи не з'явиться у реальному класі b / c, він не дає ніякої користі від використання реалізованої за замовчуванням реалізації Object.equals ().

Якщо ви тільки починаєте роботу з цими матеріалами, я настійно рекомендую Ефективну книгу Java Джошуа Блоха. Це чудове прочитання і висвітлює подібні речі (плюс як правильно реалізувати рівняння (), коли ви намагаєтесь зробити більше, ніж порівняння на основі ідентичності)


З цією метою я намагався перевірити, чи є об’єкт однакового значення в ArrayList. Я припускаю, що це свого роду злом. Дякую за рекомендацію книги
Mantas Vidutis

3

Ярлик від JavaDoc :

булева містить (Object o)

Повертає істину, якщо цей список містить вказаний елемент. Більш формально, повертає істину тоді і тільки тоді, коли цей список містить принаймні один елемент e такий, що (o == null? E == null: o.equals (e))

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.