Cara mengganti metode sama dengan di Jawa

108

Saya mencoba untuk mengganti metode sama di Jawa. Saya memiliki kelas Peopleyang pada dasarnya memiliki 2 bidang data namedan age. Sekarang saya ingin menimpaequals metode sehingga saya dapat memeriksa antara 2 objek Orang.

Kode saya adalah sebagai berikut

public boolean equals(People other){
    boolean result;
    if((other == null) || (getClass() != other.getClass())){
        result = false;
    } // end if
    else{
        People otherPeople = (People)other;
        result = name.equals(other.name) &&  age.equals(other.age);
    } // end else

    return result;
} // end equals

Tapi saat saya menulis age.equals(other.age) itu memberi saya kesalahan karena metode yang sama hanya dapat membandingkan String dan usia adalah Integer.

Larutan

Saya menggunakan ==operator seperti yang disarankan dan masalah saya terpecahkan.

berang-berang
sumber
3
Hei bagaimana dengan ini.age == other.age? :)
denis.solonenko
1
Apa tipe data untuk usia? int OR Integer? Juga, versi JDK apa yang Anda gunakan?
Manish
2
"as equals method hanya bisa membandingkan String" - Siapa bilang metode sama hanya bisa membandingkan String? metode sama dengan kelas Objek dan setiap kelas yang dibuat akan memiliki implementasi yang sama secara default. Anda dapat menelepon yang sama di kelas Java APA PUN
Manish

Jawaban:

127
//Written by K@stackoverflow
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        ArrayList<Person> people = new ArrayList<Person>();
        people.add(new Person("Subash Adhikari", 28));
        people.add(new Person("K", 28));
        people.add(new Person("StackOverflow", 4));
        people.add(new Person("Subash Adhikari", 28));

        for (int i = 0; i < people.size() - 1; i++) {
            for (int y = i + 1; y <= people.size() - 1; y++) {
                boolean check = people.get(i).equals(people.get(y));

                System.out.println("-- " + people.get(i).getName() + " - VS - " + people.get(y).getName());
                System.out.println(check);
            }
        }
    }
}

//written by K@stackoverflow
    public class Person {
        private String name;
        private int age;

        public Person(String name, int age){
            this.name = name;
            this.age = age;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }

            
if (obj.getClass() != this.getClass()) {
                return false;
            }



            final Person other = (Person) obj;
            if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
                return false;
            }

            if (this.age != other.age) {
                return false;
            }

            return true;
        }

        @Override
        public int hashCode() {
            int hash = 3;
            hash = 53 * hash + (this.name != null ? this.name.hashCode() : 0);
            hash = 53 * hash + this.age;
            return hash;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

Keluaran:

Lari:

- Subash Adhikari - VS - K salah

- Subash Adhikari - VS - StackOverflow false

- Subash Adhikari - VS - Subash Adhikari benar

- K - VS - StackOverflow false

- K - VS - Subash Adhikari palsu

- StackOverflow - VS - Subash Adhikari palsu

- BUILD SUKSES (total waktu: 0 detik)

Kim
sumber
7
apa hash = 53 * hashmengapa kamu menggunakan itu?
kittu
2
Menggunakan getClass()akan menyebabkan masalah jika kelas tersebut mendapat subkelas, dan dibandingkan dengan objek kelas super.
Tuxdude
1
mungkin karena 53 adalah bilangan prima , lihat jawaban ini stackoverflow.com/a/27609/3425489 , komentarnya saat memilih bilangan dihashCode()
Shantaram Tupe
1
Jawaban pemenang untuk pertanyaan ini memiliki penjelasan yang sangat bagus tentang mengapa Anda mengganti hashCode () stackoverflow.com/a/27609/1992108
Pegasaurus
7
Pertimbangkan untuk menggunakan if (getClass ()! = Obj.getClass ()) ... daripada menggunakan instanceofoperator atau isAssignableFrom. Ini akan membutuhkan pencocokan jenis tepat, bukan pencocokan subjenis. - Persyaratan simetris. Juga untuk membandingkan Stringatau tipe Objek lainnya, Anda dapat menggunakan Objects.equals(this.name,other.name).
YoYo
22

Memperkenalkan tanda tangan metode baru yang mengubah jenis parameter disebut overloading :

public boolean equals(People other){

Ini Peopleberbeda dengan Object.

Ketika tanda tangan metode tetap sama dengan superclassnya, itu disebut overriding dan @Overrideanotasi membantu membedakan keduanya pada waktu kompilasi:

@Override
public boolean equals(Object other){

Tanpa melihat pernyataan sebenarnya dari age, sulit untuk mengatakan mengapa kesalahan itu muncul.

fortran
sumber
18

Saya tidak yakin dengan detailnya karena Anda belum memposting seluruh kode, tetapi:

  • ingatlah untuk menimpa hashCode()juga
  • yang equalsmetode harus memiliki Object, tidak Peoplesebagai jenis argumen. Saat ini Anda membebani, tidak menimpa, metode sama, yang mungkin bukan yang Anda inginkan, terutama mengingat Anda memeriksa tipenya nanti.
  • Anda dapat menggunakan instanceofuntuk memeriksa apakah itu adalah objek Orang misalnyaif (!(other instanceof People)) { result = false;}
  • equalsdigunakan untuk semua objek, tapi tidak primitif. Saya pikir maksud Anda usia adalah int(primitif), dalam hal ini gunakan saja ==. Perhatikan bahwa Integer (dengan huruf besar 'I') adalah Objek yang harus dibandingkan dengan sama.

Lihat Masalah apa yang harus dipertimbangkan saat mengganti sama dengan dan kode hash di Java? untuk lebih jelasnya.

Adrian Mouat
sumber
12
@Override
public boolean equals(Object that){
  if(this == that) return true;//if both of them points the same address in memory

  if(!(that instanceof People)) return false; // if "that" is not a People or a childclass

  People thatPeople = (People)that; // than we can cast it to People safely

  return this.name.equals(thatPeople.name) && this.age == thatPeople.age;// if they have the same name and same age, then the 2 objects are equal unless they're pointing to different memory adresses
}
NeverJr
sumber
12

Butir 10: Patuhi kontrak umum saat mengganti yang sama

Menurut Java Efektif , Mengganti equalsmetode tampaknya sederhana, tetapi ada banyak cara untuk membuatnya salah, dan konsekuensinya bisa mengerikan. Cara termudah untuk menghindari masalah adalah dengan tidak mengganti equalsmetode, dalam hal ini setiap instance kelas hanya sama dengan dirinya sendiri. Ini adalah hal yang benar untuk dilakukan jika salah satu dari kondisi berikut berlaku:

  • Setiap instance kelas secara inheren unik . Ini berlaku untuk kelas seperti Thread yang mewakili entitas aktif daripada nilai. Implementasi sama yang disediakan oleh Object memiliki perilaku yang tepat untuk kelas-kelas ini.

  • Kelas tidak perlu memberikan pengujian "persamaan logis". Misalnya, java.util.regex.Pattern dapat diganti sama dengan untuk memeriksa apakah dua contoh Pola mewakili ekspresi reguler yang persis sama, tetapi perancang tidak berpikir bahwa klien akan membutuhkan atau menginginkan fungsionalitas ini. Dalam keadaan ini, implementasi yang sama yang diwarisi dari Object sangat ideal.

  • Superkelas telah menimpa sama, dan perilaku kelas super sesuai untuk kelas ini. Misalnya, sebagian besar implementasi Set mewarisi implementasi yang sama dari AbstractSet, implementasi List dari AbstractList, dan implementasi Map dari AbstractMap.

  • Kelas ini privat atau paket-privat , dan Anda yakin bahwa metode yang sama tidak akan pernah dipanggil. Jika Anda sangat menghindari risiko, Anda dapat mengganti metode sama dengan untuk memastikannya tidak dipanggil secara tidak sengaja:

The equalsMetode mengimplementasikan relasi ekivalen. Ini memiliki properti ini:

  • Refleksif: Untuk nilai referensi bukan nol x, x.equals(x)harus mengembalikan true.

  • Symmetric: Untuk nilai referensi bukan null xdan y, x.equals(y)harus mengembalikan true jika dan hanya jika y.equals (x) mengembalikan true.

  • Transitif: Untuk setiap nilai referensi non-null x, y, z, jika x.equals(y)kembali truedan y.equals(z)kembali true, maka x.equals(z)harus kembali true.

  • Konsisten: Untuk nilai referensi bukan nol xdan y, beberapa pemanggilan x.equals(y)harus secara konsisten mengembalikan trueatau kembali secara konsisten false, asalkan tidak ada informasi yang digunakan dalam perbandingan yang sama yang dimodifikasi.

  • Untuk nilai referensi bukan nol x, x.equals(null)harus dikembalikan false.

Berikut resep untuk metode sama berkualitas tinggi:

  1. Gunakan ==operator untuk memeriksa apakah argumennya adalah referensi ke objek ini. Jika demikian, kembalikan true. Ini hanyalah pengoptimalan kinerja tetapi layak dilakukan jika perbandingannya berpotensi mahal.

  2. Gunakan instanceofoperator untuk memeriksa apakah argumen memiliki tipe yang benar. Jika tidak, kembalikan false. Biasanya, tipe yang benar adalah kelas tempat metode tersebut terjadi. Terkadang, ini adalah beberapa antarmuka yang diimplementasikan oleh kelas ini. Gunakan antarmuka jika kelas mengimplementasikan antarmuka yang menyempurnakan kontrak yang sama untuk mengizinkan perbandingan antar kelas yang mengimplementasikan antarmuka. Antarmuka koleksi seperti Set, List, Map, dan Map.Entry memiliki properti ini.

  3. Keluarkan argumen ke tipe yang benar. Karena pemeran ini didahului dengan contoh pengujian, maka dijamin berhasil.

  4. Untuk setiap bidang "signifikan" di kelas, periksa apakah bidang argumen tersebut cocok dengan bidang terkait dari objek ini. Jika semua tes ini berhasil, kembalikan nilai true; jika tidak, kembalikan false. Jika tipe di Langkah 2 adalah antarmuka, Anda harus mengakses kolom argumen melalui metode antarmuka; jika tipenya adalah kelas, Anda mungkin dapat mengakses bidang secara langsung, bergantung pada aksesibilitasnya.

  5. Untuk bidang primitif yang tipenya bukan floatatau double, gunakan ==operator untuk perbandingan; untuk bidang referensi objek, panggil equalsmetode secara rekursif; untuk floatbidang, gunakan Float.compare(float, float)metode statis ; dan untuk doubleladang, gunakan Double.compare(double, double). Perlakuan khusus bidang apung dan ganda diperlukan oleh keberadaan Float.NaN, -0.0fdan nilai ganda analog; Meskipun Anda dapat membandingkan floatdan doublekolom dengan metode statis Float.equalsdan Double.equals, ini akan memerlukan autoboxing pada setiap perbandingan, yang akan memiliki kinerja yang buruk. Untuk arraybidang, terapkan pedoman ini ke setiap elemen. Jika setiap elemen dalam kolom array signifikan, gunakan salah satu Arrays.equalsmetode.

  6. Beberapa bidang referensi objek mungkin berisi secara sah null. Untuk menghindari kemungkinan a NullPointerException, periksa bidang tersebut untuk persamaan menggunakan metode statis Objects.equals(Object, Object).

    // Class with a typical equals method
    
    public final class PhoneNumber {
    
        private final short areaCode, prefix, lineNum;
    
        public PhoneNumber(int areaCode, int prefix, int lineNum) {
    
            this.areaCode = rangeCheck(areaCode,  999, "area code");
    
            this.prefix   = rangeCheck(prefix,    999, "prefix");
    
            this.lineNum  = rangeCheck(lineNum,  9999, "line num");
    
        }
    
        private static short rangeCheck(int val, int max, String arg) {
    
            if (val < 0 || val > max)
    
               throw new IllegalArgumentException(arg + ": " + val);
    
            return (short) val;
    
        }
    
        @Override public boolean equals(Object o) {
            if (o == this)
                return true;
            if (!(o instanceof PhoneNumber))
                return false;
            PhoneNumber pn = (PhoneNumber)o;
            return pn.lineNum == lineNum && pn.prefix == prefix
                    && pn.areaCode == areaCode;
        }
        ... // Remainder omitted
    
    }

sumber
1
Jangan lupa untuk menyebutkan bahwa Anda juga harus menimpa hashCode(). Juga catatan, bahwa sejak Java7 menulis equals()dan hashCode()metode telah menjadi jauh lebih mudah dengan menggunakan Objects.equals(), Arrays.equals()dan Objects.hashCode(), Arrays.hashCode().
Arnold Schrijver
3
Pertimbangkan untuk menggunakan if (getClass() != obj.getClass()) ...daripada menggunakan operator instanceof. Ini akan membutuhkan pencocokan jenis tepat , bukan pencocokan subjenis. - Persyaratan simetris.
YoYo
@YoYo benar ... menggunakan instanceof dapat menggagalkan properti simetris. Jika o adalah subclass PhoneNumber seperti mungkin PhoneNumberWithExtension, dan menimpanya sama dengan cara yang sama dengan menggunakan instanceof, maka o.equals (this) akan gagal dalam pengujian instanceof sementara PhoneNumber.equals akan melewatinya dan mengembalikan true (dengan asumsi semua bidang PhoneNumber lainnya adalah sama).
ldkronos
5

Karena saya menebak ageadalah tipe int:

public boolean equals(Object other){
    boolean result;
    if((other == null) || (getClass() != other.getClass())){
        result = false;
    } // end if
    else{
        People otherPeople = (People)other;
        result = name.equals(otherPeople.name) &&  age == otherPeople.age;
    } // end else

    return result;
} // end equals
Luchian Grigore
sumber
Hal ini akan menghasilkan NullPointerExceptionjika nameadalah null.
orien
@orien Bukan masalah besar, mungkin dalam kontrak yang nametidak pernah diberi nullnilai ...
fortran
@fortran Jadi ... mungkin ini bukan masalah besar;)
orien
5

Saat membandingkan objek di Java, Anda melakukan pemeriksaan semantik , membandingkan tipe dan status identifikasi objek ke:

  • sendiri (contoh yang sama)
  • itu sendiri (kloning, atau salinan yang direkonstruksi)
  • objek lain dari jenis yang berbeda
  • objek lain dengan tipe yang sama
  • null

Aturan:

  • Simetri :a.equals(b) == b.equals(a)
  • equals()selalu menghasilkan trueatau false, tapi tidak pernah NullpointerException, ClassCastExceptionatau lemparan lainnya

Perbandingan:

  • Jenis pemeriksaan : kedua contoh harus berjenis sama , artinya Anda harus membandingkan kelas aktual untuk kesetaraan. Ini sering tidak diterapkan dengan benar, ketika pengembang menggunakan instanceofuntuk perbandingan tipe (yang hanya berfungsi selama tidak ada subkelas, dan melanggar aturan simetri ketika A extends B -> a instanceof b != b instanceof a).
  • Pemeriksaan semantik dari status pengidentifikasi : Pastikan Anda memahami dengan status mana instance diidentifikasi. Orang dapat dikenali dari nomor jaminan sosialnya, tetapi tidak berdasarkan warna rambut (dapat diwarnai), nama (dapat diubah) atau usia (berubah-ubah setiap saat). Hanya dengan objek nilai Anda harus membandingkan status lengkap (semua bidang non-sementara), jika tidak, centang hanya apa yang mengidentifikasi instance.

Untuk Personkelas Anda :

public boolean equals(Object obj) {

    // same instance
    if (obj == this) {
        return true;
    }
    // null
    if (obj == null) {
        return false;
    }
    // type
    if (!getClass().equals(obj.getClass())) {
        return false;
    }
    // cast and compare state
    Person other = (Person) obj;
    return Objects.equals(name, other.name) && Objects.equals(age, other.age);
}

Kelas utilitas umum yang dapat digunakan kembali:

public final class Equals {

    private Equals() {
        // private constructor, no instances allowed
    }

    /**
     * Convenience equals implementation, does the object equality, null and type checking, and comparison of the identifying state
     *
     * @param instance       object instance (where the equals() is implemented)
     * @param other          other instance to compare to
     * @param stateAccessors stateAccessors for state to compare, optional
     * @param <T>            instance type
     * @return true when equals, false otherwise
     */
    public static <T> boolean as(T instance, Object other, Function<? super T, Object>... stateAccessors) {
        if (instance == null) {
            return other == null;
        }
        if (instance == other) {
            return true;
        }
        if (other == null) {
            return false;
        }
        if (!instance.getClass().equals(other.getClass())) {
            return false;
        }
        if (stateAccessors == null) {
            return true;
        }
        return Stream.of(stateAccessors).allMatch(s -> Objects.equals(s.apply(instance), s.apply((T) other)));
    }
}

Untuk Personkelas Anda , menggunakan kelas utilitas ini:

public boolean equals(Object obj) {
    return Equals.as(this, obj, t -> t.name, t -> t.age);
}
Peter Walser
sumber
1

jika age int Anda harus menggunakan == jika itu adalah objek Integer maka Anda dapat menggunakan equals (). Anda juga perlu menerapkan metode kode hash jika Anda mengganti sama. Rincian kontrak tersedia di javadoc Object dan juga di berbagai halaman web.

Ashwinee K Jha
sumber
0

Inilah solusi yang baru-baru ini saya gunakan:

public class Test {
    public String a;
    public long b;
    public Date c;
    public String d;
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof Test)) {
            return false;
        }
        Test testOther = (Test) obj;
        return (a != null ? a.equals(testOther.a) : testOther.a == null)
                && (b == testOther.b)
                && (c != null ? c.equals(testOther.c) : testOther.c == null)
                && (d != null ? d.equals(testOther.d) : testOther.d == null);
    }

}
SSharma
sumber