Java'da eşittir yöntemi nasıl geçersiz kılınır


108

Java'da eşittir yöntemini geçersiz kılmaya çalışıyorum. PeopleTemelde 2 veri alanı olan bir sınıfım var nameve age. Şimdi equals, 2 Kişi nesnesini kontrol edebilmek için yöntemi geçersiz kılmak istiyorum .

Kodum aşağıdaki gibidir

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

Ancak yazdığımda age.equals(other.age)bana hata veriyor çünkü eşittir yöntemi yalnızca String'i karşılaştırabilir ve yaş Tamsayı.

Çözüm

==Operatörü önerildiği gibi kullandım ve sorunum çözüldü.


3
Hey this.age == other.age? :)
denis.solonenko

1
Yaş için veri türü nedir? int OR Tamsayı? Ayrıca, JDK'nın hangi sürümünü kullanıyorsunuz?
Manish

2
"eşittir yöntemi yalnızca String'i karşılaştırabilir" - Eşittir yönteminin yalnızca String'i karşılaştırabileceğini kim söyledi? equals yöntemi Object sınıfına aittir ve oluşturulan herhangi bir sınıfın varsayılan olarak equals uygulaması olacaktır. HERHANGİ BİR Java sınıfında eşittir diyebilirsiniz
Manish

Yanıtlar:


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

Çıktı:

Çalıştırmak:

- Subash Adhikari - VS - K yanlış

- Subash Adhikari - VS - StackOverflow false

- Subash Adhikari - VS - Subash Adhikari true

- K - VS - StackOverflow yanlış

- K - VS - Subash Adhikari yanlış

- StackOverflow - VS - Subash Adhikari yanlış

- BAŞARILI OLUŞTURUN (toplam süre: 0 saniye)


7
nedir hash = 53 * hashbu kullanıyorsunuz neden?
kittu

2
Kullanımı getClass(), sınıf alt sınıflara ayrılırsa ve süper sınıfın bir nesnesiyle karşılaştırılırsa sorunlara neden olur.
Tuxdude

1
bcoz olabilir 53 olan asal sayı , bu cevap bir göz stackoverflow.com/a/27609/3425489 , o sayıları seçerken yorumladıhashCode()
Shantaram Tupe

1
Bu sorunun kazanan cevabı, hashCode () stackoverflow.com/a/27609/1992108
Pegasaurus

7
Veya instanceofoperatörünü kullanmak yerine if (getClass ()! = Obj.getClass ()) ... kullanmayı düşünün isAssignableFrom. Bu, alt tür eşleşmesi yerine tam tür eşlemesi gerektirir. - Simetrik gereksinim. Ayrıca karşılaştırmak Stringveya diğer Nesne türlerini kullanabilirsiniz Objects.equals(this.name,other.name).
YoYo

22

Parametre türlerini değiştiren yeni bir yöntem imzasının sunulmasına aşırı yükleme adı verilir :

public boolean equals(People other){

İşte Peoplebundan farklı Object.

Bir yöntem imzası, üst sınıfınınkiyle aynı kaldığında, buna geçersiz kılma adı verilir ve @Overrideek açıklama, ikisini derleme zamanında ayırt etmeye yardımcı olur:

@Override
public boolean equals(Object other){

Gerçek beyanını görmeden, agehatanın neden ortaya çıktığını söylemek zordur.


18

Kodun tamamını göndermediğiniz için ayrıntılardan emin değilim, ancak:

  • geçersiz kılmayı unutma hashCode() da
  • equalsyöntem olmalıdır Object, değilPeople onun argümanı türü olarak. Şu anda eşittir yöntemini aşırı yüklüyorsunuz, geçersiz kılmıyorsunuz, ki bu muhtemelen istediğiniz şey değildir, özellikle de türünü daha sonra kontrol ettiğinizde.
  • instanceofbir Kişiler nesnesi olup olmadığını kontrol etmek için kullanabilirsiniz .if (!(other instanceof People)) { result = false;}
  • equalstüm nesneler için kullanılır, ancak ilkeller için kullanılmaz. Sanırım yaşın int(ilkel) olduğunu kastediyorsunuz , bu durumda sadece kullanın ==. Bir Tamsayının (büyük 'I') eşitlerle karşılaştırılması gereken bir Nesne olduğuna dikkat edin.

Bkz Java eşittir ve hashCode geçersiz kılmak için konuların ele alınmasını gerektiren ne olacak? daha fazla ayrıntı için.


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
}

12

Madde 10: Eşitleri geçersiz kılarken genel sözleşmeye uyun

Etkili Java'ya göre , equalsyöntemi geçersiz kılmak basit görünüyor, ancak onu yanlış yapmanın birçok yolu var ve sonuçları korkunç olabilir. Sorunları önlemenin en kolay yolu, equalsyöntemi geçersiz kılmak değildir ; bu durumda, sınıfın her örneği yalnızca kendisine eşittir. Aşağıdaki koşullardan herhangi biri geçerliyse yapılacak doğru şey budur:

  • Sınıfın her bir örneği doğası gereği benzersizdir . Bu, değerler yerine aktif varlıkları temsil eden Thread gibi sınıflar için geçerlidir. Object tarafından sağlanan eşittir uygulaması bu sınıflar için tam olarak doğru davranışa sahiptir.

  • Sınıfın “mantıksal eşitlik” testi sağlamasına gerek yoktur. Örneğin, java.util.regex.Pattern, iki Desen örneğinin tam olarak aynı normal ifadeyi temsil edip etmediğini kontrol etmek için eşitleri geçersiz kılabilirdi, ancak tasarımcılar istemcilerin bu işlevselliğe ihtiyaç duyacağını veya bunu isteyeceğini düşünmediler. Bu koşullar altında, Object'ten miras alınan eşittir uygulaması idealdir.

  • Bir üst sınıf zaten eşittir geçersiz kılındı ve üst sınıf davranışı bu sınıf için uygundur. Örneğin, çoğu Set uygulaması, equals uygulamasını AbstractSet'ten, List uygulamalarını AbstractList'ten ve Map uygulamalarını AbstractMap'ten devralır.

  • Sınıf özel veya paket- özeldir ve eşittir yönteminin asla çağrılmayacağından eminsiniz. Riskten aşırı derecede kaçınıyorsanız, yanlışlıkla çağrılmamasını sağlamak için eşittir yöntemini geçersiz kılabilirsiniz:

equalsYöntem, bir eşdeğerlik ilişkisi uygular. Şu özelliklere sahiptir:

  • Dönüşlü: Herhangi bir boş olmayan referans değeri için x, x.equals(x)sonuç döndürmelidir.

  • Simetrik: Boş olmayan tüm referans değerleri için xve y, x.equals(y)ancak ve ancak y.equals (x) true döndürürse true döndürmelidir.

  • Geçişli: Herhangi bir boş olmayan referans değerleri için x, y, z, eğer x.equals(y)geri dönüş trueve y.equals(z)geri döner true, daha sonra x.equals(z)geri dönmelidir true.

  • Tutarlı: Eşittir karşılaştırmalarında kullanılan hiçbir bilginin değiştirilmemesi koşuluyla , boş olmayan tüm referans değerleri için xve ybirden çok çağrının x.equals(y)tutarlı bir şekilde döndürülmesi trueveya sürekli olarak döndürülmesi gerekir false.

  • Bir boş olmayan referans değeri için x, x.equals(null)geri dönmelidir false.

İşte yüksek kaliteli eşittir yöntemi için bir tarif:

  1. ==Argümanın bu nesneye bir başvuru olup olmadığını kontrol etmek için operatörü kullanın . Eğer öyleyse, doğruya dönün. Bu sadece bir performans optimizasyonudur, ancak karşılaştırma potansiyel olarak pahalıysa yapmaya değer bir işlemdir.

  2. instanceofBağımsız değişkenin doğru türe sahip olup olmadığını kontrol etmek için operatörü kullanın . Değilse, yanlış döndür. Tipik olarak, doğru tür, yöntemin gerçekleştiği sınıftır. Bazen, bu sınıf tarafından uygulanan bir arayüzdür. Sınıf, arabirimi uygulayan sınıflar arasında karşılaştırmalara izin vermek için eşittir sözleşmesini iyileştiren bir arabirim uygularsa bir arabirim kullanın. Set, List, Map ve Map.Entry gibi koleksiyon arayüzleri bu özelliğe sahiptir.

  3. Bağımsız değişkeni doğru türe çevirin. Bu dökümden önce bir test örneği olduğundan, başarılı olacağı garanti edilir.

  4. Sınıftaki her "önemli" alan için, bağımsız değişkenin bu alanının bu nesnenin karşılık gelen alanıyla eşleşip eşleşmediğini kontrol edin. Tüm bu testler başarılı olursa, true dönün; aksi takdirde false döndür. Adım 2'deki tür bir arayüz ise, argümanın alanlarına arayüz yöntemleri aracılığıyla erişmelisiniz; tür bir sınıfsa, erişilebilirliklerine bağlı olarak alanlara doğrudan erişebilirsiniz.

  5. Türü floatveya olmayan ilkel alanlar için, karşılaştırmalar doubleiçin ==operatörü kullanın ; nesne başvuru alanları için equalsyöntemi özyinelemeli olarak çağırın ; için floatalanlar, durgun kullanmak Float.compare(float, float)yöntemi; ve doublealanlar için kullanın Double.compare(double, double). Şamandıra ve çift alanlarının özel tedavi varlığı zorunlu hale getirir Float.NaN, -0.0fve benzer çift değerleri; Statik yöntemlerle karşılaştırabilir floatve doublealanları karşılaştırabilirsiniz ve bu, her karşılaştırmada otomatik kutulamayı gerektirir Float.equalsve Double.equalsbu da performansı düşüktür. İçin arrayalanlar, her öğe için bu yönergeleri uygulayın. Bir dizi alanındaki her öğe önemliyse, Arrays.equalsyöntemlerden birini kullanın .

  6. Bazı nesne referans alanları yasal olarak içerebilir null. A olasılığından kaçınmak için NullPointerException, statik yöntemi kullanarak bu tür alanların eşitliğini kontrol edin 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
    
    }

1
Geçersiz kılmanız hashCode()gerektiğini de söylemeyi unutmayın . Ayrıca, Java7 yazımının equals()ve hashCode()yöntemlerinin Objects.equals(), Arrays.equals()ve Objects.hashCode(), kullanılarak çok daha kolay hale geldiğine dikkat edin Arrays.hashCode().
Arnold Schrijver

3
İnstanceof if (getClass() != obj.getClass()) ...operatörünü kullanmak yerine kullanmayı düşünün . Bu, alt tür eşleşmesi yerine tam tür eşlemesi gerektirir . - Simetrik gereksinim.
YoYo

@YoYo doğru ... instanceof kullanımı simetrik özelliği bozabilir. O, PhoneNumberWithExtension gibi bir PhoneNumber alt sınıfı ise ve instanceof kullanarak aynı şekilde geçersiz kılarsa, o.equals (bu) test örneğinde başarısız olurken PhoneNumber.equals geçer ve true döndürür (diğer tüm PhoneNumber alanları varsayılarak) eşittir).
ldkronos

5

Tahmin ediyorum bu yana agetiptedir 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

Bu, bir NullPointerExceptionif nameile sonuçlanacaktır null.
orien

@orien Büyük bir anlaşma değil, belki de sözleşmede namehiçbir zaman atanmamışnull değer ...
fortran

@fortran Yani ... belki bu önemli bir şey değil;)
orien

5

Java'da nesneleri karşılaştırırken, türü karşılaştırarak ve durumu tanımlayarak anlamsal bir kontrol yaparsınız. :

  • kendisi (aynı örnek)
  • kendisi (klon veya yeniden oluşturulmuş kopya)
  • farklı türdeki diğer nesneler
  • aynı türden diğer nesneler
  • null

Kurallar:

  • Simetri :a.equals(b) == b.equals(a)
  • equals() her zaman verir true ya false, ama asla bir NullpointerException, ClassCastExceptionya da başka herhangi throwable

Karşılaştırma:

  • Tür kontrolü : her iki örneğin de aynı türde , yani eşitlik için gerçek sınıfları karşılaştırmanız gerekir. Geliştiriciler instanceoftür karşılaştırması için kullandıklarında (bu yalnızca alt sınıflar olmadığı sürece çalışır ve simetri kuralını ihlal ettiğinde A extends B -> a instanceof b != b instanceof a).
  • Durumun anlamsal kontrolü : Örneklerin hangi durumla tanımlandığını anladığınızdan emin olun. Kişiler sosyal güvenlik numaralarına göre tanımlanabilir, ancak saç rengine (boyanabilir), ismine (değiştirilebilir) veya yaşına (her zaman değişir) göre tanımlanamaz. Yalnızca değer nesneleriyle tam durumu (tüm geçici olmayan alanlar) karşılaştırmalısınız, aksi takdirde yalnızca örneği tanımlayan şeyi kontrol edin.

Senin için Person sınıfta:

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

Yeniden kullanılabilir, genel hizmet sınıfı:

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

Senin için Personsınıf, bu yarar sınıfını kullanarak:

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

1

yaş int ise == kullanmalısınız eğer bu Tamsayı nesnesiyse, eşittir () kullanabilirsiniz. Eşitleri geçersiz kılarsanız, hashcode yöntemini de uygulamanız gerekir. Sözleşmenin ayrıntıları Object javadoc'unda ve ayrıca web'deki çeşitli sayfalarda mevcuttur.


0

İşte son zamanlarda kullandığım çözüm:

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

}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.