Rabu, 14 Desember 2011

Kesamaan dan Perbandingan (Java)


Diskusi kita tentang metode pada interface Collection sebelumnya mengasumsikan bahwa dua objek dianggap "sama". Misalnya metode kol.contains(objek) dan kol.remove(objek) mencari item dalam koleksi yang sama dengan objek. Akan tetapi, kesamaan bukan sesuatu yang mudah.

Teknik yang paling umum untuk menguji kesamaan (yaitu menggunakan operator ==) sering kali tidak bisa digunakan untuk objek. Operator == yang digunakan pada objek hanya membandingkan apakah objek tersebut memiliki alamat memori yang sama. Biasanya, kita ingin supaya kesamaan berarti isi objeknya sama (bukan alamat memorinya).

Dua nilai String dianggap sama jika keduanya memiliki urutan karakter yang sama. Persoalan di mana karakter tersebut disimpan di dalam memori tentunya tidak relevan. Dua nilai bertipe Date dianggap sama jika isinya adalah waktu yang sama.

Kelas Object memiliki metode bernilai boolean yaitu equals(Object) untuk menguji apakah satu objek berisi sama dengan objek lain.

Di dalam koleksi, dua objek obj1 dan obj2 dianggap sama jika keduanya bernilai null atau jika keduanya bernilai tidak nul danobj1.equals(obj2) bernilai true.

Dalam kelas Object, obj1.equals(obj2) didefinisikan sebagai obj1 == obj2. Akan tetapi pada hampir semua kelas turunanObject, definisi ini tidak masuk akal, dan biasanya dibebanlebihkan (overload).

Kelas String misalnya, membebanlebihkan equals() sehingga untuk str.equals(obj) bernilai sama jika urutan karakter objsama dengan urutan karakter str.

Jika kita menulis kelas sendiri, kita mungkin ingin mendefinisikan metode equals() sendiri pada kelas tersebut, sehingga metode kesamaan bisa berjalan sesuai dengan yang kita inginkan. Misalnya kelas Kartu akan bekerja dengan benar jika digunakan dalam koleksi bisa dibuat seperti :
public class Kartu {  // Kelas untuk kartu mainan
    int lambang;  // Nomor 0 hingga 3 untuk lambangnya :
                       // wajik, diamon, keriting atau hati.
    int angka; // Angka 1 hingga 13
 
    public boolean equals(Object obj) {
        if (obj == null || ! (obj instanceof  Kartu) ) {
            // obj tidak sama dengan Kartu ini jika obj
            // tidak bertipe Kartu, atau isinya null
            return false;
        }
        else {
            Kartu lain = (Kartu)obj;  // Type-cast obj ke Kartu
            if (lambang == lain.lambang && angka == lain.angka) {
                // Kartu lain berlambang dan berangka sama dengan
                // kartu ini, artinya kedua kartu sama
                return true;
            }
            else
                return false;
        }
    }
    ... // metode dan konstruktor lain
}

Tanpa metode equals() dalam kelas ini, metode contains() dan remove() dalam interface Collection tidak akan bekerja dengan baik untuk kelas Kartu.

Masalah yang sama akan muncul ketika item dalam koleksi akan diurutkan. Pengurutan artinya mengatur urutan item dalam aturan tertentu. Masalahnya, tidak ada aturan "menaik" dalam objek. Sebelum objek bisa diurutkan, metode tertentu harus dibuat untuk membandingkan objek. Objek yang akan dibandingkan harus mengimplementasikan interfacejava.lang.Comparable. Interface ini mendefinisikan satu metode, yaitu :
public int compareTo(Object obj)

Nilai yang dikembalikan obj1.compareTo(obj2) bernilai nol jika kedua objek berisi sama (atau jika obj1.equals(obj2) bernilai benar). Keluarannya bernilai negatif jika obj1 lebih kecil dari obj2, atau jika diurutkan dalam urutan menaik obj1 akan muncul sebelum obj2. Keluarannya bernilai positif jika obj1 lebih besar dari obj2 atau jika diurutkan dalam urutan menaik obj1 muncul setelah obj2.

Kelas String mengimplementasikan interface Comparable dan memiliki metode compareTo dengan cara seperti di atas. Jika kita ingin membuat kelas sendiri dan ingin mengurut objek pada kelas itu, kita juga harus mengimplementasikan objek itu dengan cara yang sama. Misalnya :
class NamaLengkap implements Comparable {
    // Melambangkan nama lengkap yang terdiri dari
    // nama depan dan nama belakang
    String namaDepan, namaBelakang;
 
    public boolean equals(Object obj) {
        if (obj == null || ! (obj instanceof NamaLengkap)) {
            return false;
        }
        else {
            NamaLengkap lain = (NamaLengkap)obj;
            return namaDepan.equals(lain.namaDepan)
                && namaBelakang.equals(lain.namaBelakang);
        }
    }
 
    public void compareTo(Object obj) {
        NamaLengkap lain = (NamaLengkap)obj;
        // Menyebabkan error jika obj tidak bertipe NamaLengkap
        if ( namaBelakang.compareTo(lain.namaBelakang) < 0 ) {
            // Jika namaBelakang lebih kecil dari namaBelakang objek lain
            // maka NamaLengkap ini muncul sebelum yang lain
            // Kembalikan nilai negatif
            return -1;
        }
        if ( namaBelakang.compareTo(lain.namaBelakang) > 0 ) {
            // Jika namaBelakang lebih besar dari namaBelakang objek lain
            // maka NamaLengkap ini muncul setelah yang lain
            // Kembalikan nilai positif
            return 1;
        }
        else {
            // Nama belakangnya sama, sekarang bandingkan
            // nama depannya
            return namaDepan.compareTo(lain.namaDepan);
        }
    }
    ... // metode dan konstruktor lain
}
Ada cara lain untuk membandingkan objek pada Java, yaitu dengan membuat objek lain untuk melakukan perbandingan. Objek tersebut harus mengimplementasikan java.util.Comparator yang memiliki metode :
public int compare(Object obj1, Object obj2)

Metode ini membandingkan dua objek dan mengembalikan nilai negatif, nol, atau positif, tergantung apakah obj1 muncul lebih dulu, sama, atau setelah obj2. Komparator ini berfungsi untuk membandingkan objek yang tidak memiliki interface Comparableatau untuk melakukan metode pembanding yang berbeda untuk objek yang bertipe sama.

Kita akan lihat bagaimana Comparable dan Comparator digunakan dalam koleksi dan map.

Tidak ada komentar:

Posting Komentar