Bagaimana metode ArrayList berisi () mengevaluasi objek?

303

Katakanlah saya membuat satu objek dan menambahkannya ke ArrayList. Jika saya kemudian membuat objek lain dengan input konstruktor yang persis sama, akankah contains()metode mengevaluasi dua objek menjadi sama? Asumsikan konstruktor tidak melakukan sesuatu yang lucu dengan input, dan variabel yang disimpan di kedua objek identik.

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

Apakah ini cara yang classharus diterapkan untuk mendapatkan contains()kembali true?

Mantas Vidutis
sumber

Jawaban:

339

ArrayDaftar implementsAntarmuka Daftar.

Jika Anda melihat Javadoc untukList di containsmetode Anda akan melihat bahwa itu menggunakan equals()metode untuk mengevaluasi apakah dua obyek yang sama.

Biner kutu buku
sumber
61
Untuk berjaga-jaga jika Anda berencana untuk mengganti equals (), pastikan Anda juga mengganti metode kode hash (). Jika Anda tidak ingin, hal-hal mungkin tidak berfungsi seperti yang diharapkan saat menggunakan Koleksi?
Mohd Farid
34
Ini adalah jawaban yang benar, tetapi perhatikan bahwa Anda perlu mengubah metode equals Anda untuk menerima Objectalih - alih a Thing. Jika tidak, metode equals Anda tidak akan digunakan. :)
mdierker
1
Baru saja menemukan sendiri bahwa gerhana memiliki "Hasilkan kode kode () dan sama dengan" di bawah menu Sumber.
Volodymyr Krupach
Ini menjawab pertanyaan dalam judul, tetapi bukan pertanyaan dalam deskripsi, yaitu "Jika saya kemudian membuat objek lain dengan input konstruktor yang persis sama, akankah metode berisi () mengevaluasi dua objek menjadi sama?"
robguinness
3
Collectionsmelakukan hal-hal mereka dengan cara yang dioptimalkan, yang berarti bahwa contains()pertama - tama memeriksa hashCodes dari dua objek, dan hanya kemudian memanggil equals(). Jika hashCodes berbeda (yang selalu merupakan kasus untuk dua contoh berbeda Thing), equals()metode tidak akan dipanggil. Sebagai aturan praktis, ketika Anda menimpa equals(), Anda tidak boleh lupa untuk menimpanya hashCode()juga.
Sevastyan Savanyuk
52

Saya pikir implementasi yang tepat seharusnya

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;
    }
}
ChristopheCVB
sumber
1
ifpernyataan itu tidak perlu. instanceofcukup.
Paul
@ Paul bagian mana dari pernyataan yang Anda bicarakan?
ChristopheCVB
4
The object != nullkondisi tidak diperlukan, karena object instanceof Thingpemeriksaan untuk objek menjadi tidak nol juga.
Alexander Farber
15

ArrayList menggunakan metode equals yang diterapkan di kelas (kelas case Anda) untuk melakukan perbandingan equals.

Bhushan Bhangale
sumber
12

Secara umum Anda juga harus mengganti hashCode()setiap kali Anda menimpa equals(), meskipun hanya untuk meningkatkan kinerja. HashCode()memutuskan 'ember' objek mana yang akan disortir saat melakukan perbandingan, sehingga setiap dua objek yang equal()bernilai true harus mengembalikan yang sama hashCode value(). Saya tidak dapat mengingat perilaku default hashCode()(jika mengembalikan 0 maka kode Anda harus bekerja tetapi lambat, tetapi jika mengembalikan alamat maka kode Anda akan gagal). Saya ingat beberapa kali ketika kode saya gagal karena saya lupa menimpa hashCode(). :)

alexloh
sumber
7

Ia menggunakan metode equals pada objek. Jadi kecuali Hal yang sama dengan dan menggunakan variabel yang disimpan dalam objek untuk perbandingan, itu tidak akan mengembalikan true pada contains()metode.

Yishai
sumber
6
class Thing {  
    public int value;  

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

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

Anda harus menulis:

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

Sekarang berhasil;)

Davide
sumber
6
Anda tidak boleh melakukan Hal x = (Hal) o; tanpa terlebih dahulu memeriksa apakah objek lainnya adalah null
steelshark
5

Hanya ingin mencatat bahwa implementasi berikut ini salah ketika valuebukan tipe primitif:

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

Dalam hal ini saya mengusulkan yang berikut:

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;
    }
}
Caner
sumber
bagaimana menerapkan ini sekaligus menghilangkan duplikat?
Sujay
4

Poster lain telah menjawab pertanyaan tentang bagaimana memuat () berfungsi.

Aspek yang sama pentingnya dari pertanyaan Anda adalah bagaimana menerapkan dengan benar equals (). Dan jawaban untuk ini benar-benar tergantung pada apa yang merupakan persamaan objek untuk kelas khusus ini. Dalam contoh yang Anda berikan, jika Anda memiliki dua objek berbeda yang keduanya memiliki x = 5, apakah keduanya sama? Itu benar-benar tergantung pada apa yang Anda coba lakukan.

Jika Anda hanya tertarik pada persamaan objek, maka implementasi default .equals () (yang disediakan oleh Object) hanya menggunakan identitas (yaitu ini == lainnya). Jika itu yang Anda inginkan, maka jangan implementasikan equals () di kelas Anda (biarkan diwarisi dari Object). Kode yang Anda tulis, walaupun agak benar jika Anda mencari identitas, tidak akan pernah muncul di kelas nyata b / c itu tidak memberikan manfaat dibandingkan menggunakan implementasi Object.equals () default.

Jika Anda baru memulai dengan hal ini, saya sangat merekomendasikan buku Java Efektif oleh Joshua Bloch. Ini adalah bacaan yang bagus, dan mencakup hal semacam ini (ditambah cara menerapkan dengan benar equals () ketika Anda mencoba melakukan lebih dari perbandingan berbasis identitas)

Kevin Day
sumber
Untuk tujuan saya, saya mencoba untuk melihat apakah objek dengan nilai yang sama ada di ArrayList. Saya kira ini semacam peretasan. Terima kasih atas rekomendasi buku
Mantas Vidutis
3

Pintasan dari JavaDoc :

boolean berisi (Objek o)

Mengembalikan nilai true jika daftar ini mengandung elemen yang ditentukan. Lebih formal, mengembalikan true jika dan hanya jika daftar ini mengandung setidaknya satu elemen e sedemikian rupa sehingga (o == null? E == null: o.equals (e))

DenisKolodin
sumber