Neden Java'da eşittir ve hashCode yöntemlerini geçersiz kılmalıyım?


383

Son zamanlarda bu Developer Works Belgesini okudum .

Belge tamamen tanımlamakla hashCode(), equals()etkili ve doğru bir şekilde, ancak bu iki yöntemi neden geçersiz kılmamız gerektiğini anlayamıyorum.

Bu yöntemleri etkili bir şekilde uygulama kararını nasıl alabilirim?


4
Programlamada iki harika makale vardır. Kılavuz tam olarak bunu açıklar: Ne zaman eşittir? ve Eşit değerleri geçersiz kılarken neden her zaman hashCode'u geçersiz kılmalısınız . (Uyarı, kabul edilen cevap aslında yanlış.)
aioobe

Büyük / küçük harf geçersiz kılma sadece şuna eşittir: iki aynı nesnenin farklı karma kodu olacaktır = aynı nesneler farklı gruplara gider (çoğaltma). Büyük / küçük harf geçersiz kılma hashcode: iki aynı nesne aynı hashcode'a sahip olacaktır = aynı nesne aynı kovaya gider (çoğaltma).
VdeX

Yanıtlar:


524

Joshua Bloch: Etkili Java hakkında

Equals () öğesini geçersiz kılan her sınıfta hashCode () öğesini geçersiz kılmalısınız. Bunu yapmamanız, sınıfınızın HashMap, HashSet ve Hashtable dahil olmak üzere tüm karma tabanlı koleksiyonlarla birlikte düzgün çalışmasını engelleyecek olan Object.hashCode () için genel sözleşmenin ihlaline neden olacaktır.

Geçersiz equals()kılmadan geçersiz kılsak hashCode()ve kullanmaya çalıştığımızda ne olacağını bir örnekle anlamaya çalışalım Map.

Diyelim ki böyle bir sınıfımız var ve iki nesnesi MyClasseşitse importantFieldeşittir ( tutulma ile birlikte hashCode()ve equals()tutulma ile oluşturulur)

public class MyClass {

    private final String importantField;
    private final String anotherField;

    public MyClass(final String equalField, final String anotherField) {
        this.importantField = equalField;
        this.anotherField = anotherField;
    }

    public String getEqualField() {
        return importantField;
    }

    public String getAnotherField() {
        return anotherField;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((importantField == null) ? 0 : importantField.hashCode());
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        final MyClass other = (MyClass) obj;
        if (importantField == null) {
            if (other.importantField != null)
                return false;
        } else if (!importantField.equals(other.importantField))
            return false;
        return true;
    }

}

Yalnızca geçersiz kıl equals

Sadece equalsgeçersiz kılınmışsa, myMap.put(first,someValue)ilk çağırdığınızda bir kovaya karma verir ve aradığınızda myMap.put(second,someOtherValue)başka bir kovaya karma yapar (farklı oldukları için hashCode). Eşit olmalarına rağmen, aynı kovaya hash olmadıkları için, harita bunu fark edemez ve her ikisi de haritada kalır.


Geçersiz kılma equals()durumunda geçersiz kılmak gerekli olmasa da, hashCode()iki nesnenin MyClasseşitse eşit olduğunu importantFieldancak geçersiz kılmadığımızı bildiğimiz bu özel durumda ne olacağını görelim equals().

Yalnızca geçersiz kıl hashCode

Bunun olduğunu hayal et

MyClass first = new MyClass("a","first");
MyClass second = new MyClass("a","second");

Sadece geçersiz kılarsanız , ilk hashCodeçağırdığınızda myMap.put(first,someValue)bunu alır, hesaplar hashCodeve verilen bir kovada saklar. Aradığınızda Sonra myMap.put(second,someOtherValue)o uyarınca ikinci ilk değiştirmelidir Harita Belgeler eşit olduğu için (işletme şartlarına göre).

Ama sorun haritası karmaları nedenle zaman eşittir yeniden değildi ki secondbir nesne varsa grup üzerinden ve yineler seyir kböyle second.equals(k)o kadar herhangi bulamazsınız doğrudur second.equals(first)olacaktır false.

Umarım açıktı


5
lütfen biraz daha ayrıntı verebilir misiniz, ikinci durumda, ikinci nesne neden başka bir kovaya girmeli?
Hussain Akhtar Wahid 'Ghouri'

57
Ben sadece doğru değil equals (), geçersiz kılma olmadan hashCode () geçersiz kılınamaz öneririz çünkü bu cevap sevmiyorum. İki nesnenizi eşit olarak tanımladığınız için örnek kodunuzun ("yalnızca geçersiz hashCode geçersiz kılma" bölümü) çalışmadığını söylüyorsunuz , ancak - özür dilerim - bu tanım yalnızca kafanızda. İlk örneğinizde aynı hashCode'a sahip iki eşit olmayan nesneniz var ve bu tamamen yasal. Bu nedenle equals () öğesini geçersiz kılmanızın nedeni, hashCode () öğesini zaten geçersiz kıldığınız için değil, "equals" tanımınızı kafanızdan koda taşımak istediğinizden kaynaklanmaktadır.
user2543253

11
if you think you need to override one, then you need to override both of themHata. hashCodeSınıfınız geçersiz kılsa equalsancak tersi doğru değilse geçersiz kılmanız gerekir .
akhil_mittal

4
Ben de eşittir () geçersiz kılmadan sadece hashCode () geçersiz kılmak için Tamam olduğunu düşünüyorum . Ayrıca Etkili Java ile yazılanlar : books.google.fr/…
Johnny

2
@PhantomReference, equalsjavadoc içinde yazılan sözleşmeyi yalnızca geçersiz kılmanın ihlal edeceğini unutmayın Object: "İki nesne equals(Object)yönteme göre eşitse hashCode, iki nesnenin her birine yöntemin çağrılması aynı tamsayı sonucunu üretmelidir." Elbette, tüm sözleşmelerin tüm bölümleri tüm kodlarda kullanılmaz, ancak yine de resmi olarak konuşmak gerekirse bir ihlaldir ve bunun gerçekleşmeyi bekleyen bir hata olduğunu düşünürdüm.
aioobe

264

Bir koleksiyon gibi nesnenin nasıl saklanması gerektiğini belirlemek için nesnenin hashcode değerini kullanır HashMapve HashSetkullanır ve hashcode , koleksiyonundaki nesneyi bulmak için tekrar kullanılır.

Karma alma iki adımlı bir işlemdir:

  1. Doğru kovayı bulun (kullanarak hashCode())
  2. Grupta doğru öğeyi arayın (kullanarak equals())

İşte neden geçersiz kılmamız gerektiğine dair küçük bir örnek equals()ve hashcode().

Employeeİki alanı olan bir sınıfı düşünün : yaş ve isim.

public class Employee {

    String name;
    int age;

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    @Override
    public boolean equals(Object obj) {
        if (obj == this)
            return true;
        if (!(obj instanceof Employee))
            return false;
        Employee employee = (Employee) obj;
        return employee.getAge() == this.getAge()
                && employee.getName() == this.getName();
    }

    // commented    
    /*  @Override
        public int hashCode() {
            int result=17;
            result=31*result+age;
            result=31*result+(name!=null ? name.hashCode():0);
            return result;
        }
     */
}

Şimdi bir sınıf oluşturun, Employeeiçine bir nesne ekleyin HashSetve o nesnenin var olup olmadığını test edin.

public class ClientTest {
    public static void main(String[] args) {
        Employee employee = new Employee("rajeev", 24);
        Employee employee1 = new Employee("rajeev", 25);
        Employee employee2 = new Employee("rajeev", 24);

        HashSet<Employee> employees = new HashSet<Employee>();
        employees.add(employee);
        System.out.println(employees.contains(employee2));
        System.out.println("employee.hashCode():  " + employee.hashCode()
        + "  employee2.hashCode():" + employee2.hashCode());
    }
}

Aşağıdakileri yazdıracaktır:

false
employee.hashCode():  321755204  employee2.hashCode():375890482

Şimdi uncomment hashcode()yöntemi, aynısını yürütün ve çıktı:

true
employee.hashCode():  -938387308  employee2.hashCode():-938387308

Şimdi, eğer iki nesne eşit kabul edilirse, bunların hash kodları da neden eşit olmalı? Aksi takdirde, nesneyi asla bulamazsınız çünkü sınıftaki varsayılan hashcode yöntemi Nesne equals(), iki veya daha fazla nesne eşit kabul edilecek şekilde geçersiz kılınsa bile, hemen hemen her nesne için benzersiz bir sayı bulur. . Hash kodları bunu yansıtmıyorsa , nesnelerin ne kadar eşit olduğu önemli değildir. Yani bir kez daha: İki nesne eşitse, bunların karma kodları da eşit olmalıdır.


4
Mükemmel bir örnek. Farkı açıkça gösterdi!
coderpc

3
güzel açıkladı @rajeev
VdeX

2
@VikasVerma nesnesi eşit hashcode'a eşittir eşit olmayan nesnenin eşit olmayan hashcode'u olacağı anlamına gelmez. Nesneler aslında farklıysa, ancak karma kodları aynıysa ne olur?
Ravi

1
çok güzel açıkladı :)
Rahul

4
kabul edilen cevaptan çok daha iyi cevap! Teşekkürler
dalgaların karaya

50

Equals () öğesini geçersiz kılan her sınıfta hashCode () öğesini geçersiz kılmalısınız. Bunu yapmamanız, sınıfınızın HashMap, HashSet ve Hashtable dahil olmak üzere tüm karma tabanlı koleksiyonlarla birlikte düzgün çalışmasını engelleyecek olan Object.hashCode () için genel sözleşmenin ihlaline neden olacaktır.


   dan Etkili Java Joshua Bloch tarafından,

Tanımlayarak equals()ve hashCode()tutarlı bir şekilde, karma tabanlı koleksiyonlarda sınıflarınızın anahtar olarak kullanılabilirliğini artırabilirsiniz. HashCode için API dokümanı açıkladığı gibi: "Bu yöntem, sağlananlar gibi hashtables'ın yararına desteklenmektedir java.util.Hashtable."

Bu yöntemlerin verimli bir şekilde nasıl uygulanacağı ile ilgili sorunuzun en iyi yanıtı, Etkili Java'nın 3. Bölümünü okumanızı öneririz .


4
Bu doğru cevap. Tabii ki, sınıfı hiçbir zaman karma tabanlı bir koleksiyonda kullanmazsanız, o zaman uygulanmadığınız önemli değildir hashCode().
ince

1
Daha karmaşık durumlarda, kullandığınız koleksiyonların hash kullanıp kullanmadığını asla bilemezsiniz, bu nedenle "hashCode () uygulamamanız önemli değil" ifadesinden uzak durun
Victor Sergienko

1
Eşittir () geçersiz kılmadan hashCode () geçersiz kılabilir miyim?
Johnny

@StasS, evet, kabul edilen cevabın aksine. Bu makalenin ikinci bölümündeki açıklamaya bakın:
Eşittirken

22

Basitçe söylemek gerekirse, nesne eşitliğinde referans eşitliği denetler; burada sınıfınızdaki iki örnek, özellikler eşit olduğunda hala anlamsal olarak eşit olabilir. Bu, nesnelerinizi HashMap ve Set gibi eşit ve hashcode kullanan bir kaba koyarken önemlidir . Diyelim ki bir sınıfımız var:

public class Foo {
    String id;
    String whatevs;

    Foo(String id, String whatevs) {
        this.id = id;
        this.whatevs = whatevs;
    }
}

Aynı kimliğe sahip iki örnek oluşturuyoruz :

Foo a = new Foo("id", "something");
Foo b = new Foo("id", "something else");

Eşit değerleri geçersiz kılmadan:

  • a. (b) eşittir yanlıştır çünkü bunlar iki farklı örnektir
  • a.equals (a), aynı örnek olduğu için doğrudur
  • b.equals (b), aynı örnek olduğu için doğrudur

Doğru? Belki de, eğer istediğin buysa. Ancak diyelim ki aynı kimliğe sahip nesneler, iki farklı örneğinden bağımsız olarak aynı nesne olmasını istiyoruz. Şuna eşittir (ve hashcode):

public class Foo {
    String id;
    String whatevs;

    Foo(String id, String whatevs) {
        this.id = id;
        this.whatevs = whatevs;
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof Foo) {
            return ((Foo)other).id.equals(this.id);   
        }
    }

    @Override
    public int hashCode() {
        return this.id.hashCode();
    }
}

Eşittir ve hashcode uygulamak için Guava'nın yardımcı yöntemlerini kullanmanızı tavsiye ederim


20

Kimlik eşitlik değildir.

  • operatör ==testi kimliğine eşittir .
  • equals(Object obj) yöntemi eşitlik testini karşılaştırır (yani yöntemi geçersiz kılarak eşitliği söylememiz gerekir)

Neden Java'da eşittir ve hashCode yöntemlerini geçersiz kılmalıyım?

İlk önce eşittir yönteminin kullanımını anlamalıyız.

İki nesne arasındaki kimlik farklılıklarını eşitlemek için eşittir yöntemini geçersiz kılmamız gerekir.

Örneğin:

Customer customer1=new Customer("peter");
Customer customer2=customer1;
customer1.equals(customer2); // returns true by JVM. i.e. both are refering same Object
------------------------------
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
customer1.equals(customer2); //return false by JVM i.e. we have two different peter customers.

------------------------------
Now I have overriden Customer class equals method as follows:
 @Override
    public boolean equals(Object obj) {
        if (this == obj)   // it checks references
            return true;
        if (obj == null) // checks null
            return false;
        if (getClass() != obj.getClass()) // both object are instances of same class or not
            return false;
        Customer other = (Customer) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name)) // it again using bulit in String object equals to identify the difference 
            return false;
        return true; 
    }
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
Insteady identify the Object equality by JVM, we can do it by overring equals method.
customer1.equals(customer2);  // returns true by our own logic

Şimdi hashCode yöntemi kolayca anlayabilir.

hashCode, nesneyi HashMap , HashSet gibi veri yapılarında depolamak için tamsayı üretir .

CustomerYukarıdaki gibi geçersiz kılma yöntemine sahip olduğumuzu varsayalım ,

customer1.equals(customer2);  // returns true by our own logic

Nesneyi kovalarda sakladığımızda veri yapısı ile çalışırken (kova klasör için süslü bir addır). Yerleşik karma tekniğini kullanırsak, iki müşterinin üstünde iki farklı karma kodu oluşturur. Aynı özdeş nesneyi iki farklı yerde saklıyoruz. Bu tür sorunları önlemek için, hashCode yöntemini aşağıdaki ilkelere göre de geçersiz kılmalıyız.

  • eşit olmayan örneklerin aynı karma kodu olabilir.
  • eşit örnekler aynı karma kodu döndürmelidir.

3
Son 1 saatten beri aradığım şey buydu. Harika dostum (y)
Adnan

13

Tamam, kavramı çok basit kelimelerle açıklayayım.

Öncelikle daha geniş bir perspektiften koleksiyonlarımız var ve hashmap koleksiyonlardaki veri yapısından biri.

Öncelikle hashmap'ın ne olduğunu ve ne işe yaradığını anlamak gerekirse, hem eşittir hem de hashcode yöntemini neden geçersiz kılmak zorunda olduğumuzu anlamak için.

Bir hashmap, anahtar / değer çiftlerini dizi halinde depolayan bir veri yapısıdır. 'A' içindeki her bir öğenin bir anahtar değer çifti olduğu bir [] diyelim.

Ayrıca, yukarıdaki dizideki her bir indeks, bir indekste birden fazla değere sahip olacak şekilde bağlantılı listeye bağlanabilir.

Şimdi neden bir hashmap kullanılıyor? Büyük bir dizi arasında arama yapmak zorunda kalırsak, daha sonra verimli olmayacaklarsa her birini araştırırız, bu yüzden hash tekniği bize diziyi bazı mantıkla ön işleme izin verir ve öğeleri bu mantığa göre gruplandırır.

örneğin: 1,2,3,4,5,6,7,8,9,10,11 dizimiz var ve mod 10'u bir karma fonksiyonu uyguluyoruz, böylece 1,11 birlikte gruplandırılacak. Bu nedenle, önceki dizide 11'i aramak zorunda kalsaydık, o zaman tüm diziyi yinelemeliydik, ancak gruplandırdığımızda yineleme kapsamımızı sınırlandırdık ve böylece hızı geliştirdik. Yukarıdaki tüm bilgileri saklamak için kullanılan veri yapısı basitlik için 2d dizisi olarak düşünülebilir

Şimdi yukarıdaki hashmap dışında herhangi bir Yinelenen eklemeyeceğini söyler. Eşittir ve hashcode'u geçersiz kılmamızın ana nedeni budur

Bu nedenle, hashmap'ın iç çalışmasını açıkladığı söylendiğinde, hashmap'ın hangi yöntemlere sahip olduğunu ve yukarıda açıkladığım yukarıdaki kurallara nasıl uyduğunu bulmamız gerekir.

bu nedenle hashmap'ın put (K, V) olarak adlandırılan bir yöntemi vardır ve hashmap'a göre diziyi verimli bir şekilde dağıtmak ve herhangi bir kopya eklememek için yukarıdaki kurallara uymalıdır.

bu yüzden koymak ne ilk önce değerin hangi dizine girmesi gerektiğine karar vermek için verilen anahtar için hashcode üretecektir. bu dizinde hiçbir şey yoksa, o zaman orada zaten bir şey varsa, yeni değer eklenecektir yeni değer bu dizindeki bağlantılı listenin bitiminden sonra eklenmelidir. ancak hashmap'in istenen davranışına göre hiçbir kopya eklenmemesi gerektiğini unutmayın. diyelim ki iki Tamsayı nesneniz var aa = 11, bb = 11. nesne sınıfından türetilen her nesne olarak, iki nesneyi karşılaştırmak için varsayılan uygulama, nesnenin içindeki değerleri değil referansı karşılaştırmasıdır. Dolayısıyla yukarıdaki durumda hem semantik olarak eşit olsa da eşitlik testinde başarısız olur ve aynı hashcode ve aynı değerlere sahip iki nesnenin bulunma olasılığı böylece kopyalar oluşturur. Geçersiz kılarsak, kopya eklemekten kaçınabiliriz. Ayrıca başvurabilirsinizDetay çalışması

import java.util.HashMap;


public class Employee {

String name;
String mobile;
public Employee(String name,String mobile) {
    this.name=name;
    this.mobile=mobile;
}

@Override
public int hashCode() {
    System.out.println("calling hascode method of Employee");
    String str=this.name;
    Integer sum=0;
    for(int i=0;i<str.length();i++){
        sum=sum+str.charAt(i);
    }
    return sum;

}
@Override
public boolean equals(Object obj) {
    // TODO Auto-generated method stub
    System.out.println("calling equals method of Employee");
    Employee emp=(Employee)obj;
    if(this.mobile.equalsIgnoreCase(emp.mobile)){

        System.out.println("returning true");
        return true;
    }else{
        System.out.println("returning false");
        return false;
    }


}

public static void main(String[] args) {
    // TODO Auto-generated method stub

    Employee emp=new Employee("abc", "hhh");
    Employee emp2=new Employee("abc", "hhh");
    HashMap<Employee, Employee> h=new HashMap<>();
    //for (int i=0;i<5;i++){
        h.put(emp, emp);
        h.put(emp2, emp2);

    //}

    System.out.println("----------------");
    System.out.println("size of hashmap: "+h.size());


}

}

Bir karışıklık var, neden HashMap durumunda hashCode yöntemini geçersiz kıldığımızda eşittir yöntemi geçersiz kılmak gerekiyor? Her durumda, nesnenin has kodu eşitse hashmap değeri değiştirir.
Vikas Verma

@VikasVerma hashmap, nesnelerin karma kodu eşitse herhangi bir değerin yerini almaz, yalnızca hashmap'ye yeni eklenen nesnenin yerleştirileceği dizine karar verir. Şimdi dizinde nesneler olabilir, bu nedenle çoğaltılmasını önlemek için eşittir yöntemini geçersiz kılar ve karşılaştırmada iki nesneye ne zaman eşit davranılacağını tanımlamak için mantığı yazarız. Geçersiz kılınmazsa, aynı değerlere sahip nesneler saklanacak olsa da, her iki nesnenin referansı farklı olacaktır
Chetan

11

hashCode() :

Yalnızca karma kod yöntemini geçersiz kılarsanız hiçbir şey olmaz. Çünkü hashCodeher nesne için her zaman yeni bir Object sınıfı olarak döner .

equals() :

Yalnızca eşit yöntemi geçersiz kılarsanız a.equals(b), doğru hashCode, a ve b öğelerinin aynı olması, ancak olmaması gerektiği anlamına gelir . Çünkü hashCodeyöntemi geçersiz kılmadınız.

Not: hashCode()Object sınıfı yöntemi hashCodeher nesne için her zaman yeni döndürür .

Nesnenizi karma tabanlı koleksiyonda kullanmanız gerektiğinde, hem equals()ve hem de geçersiz kılınmalıdır hashCode().


Bu ilginç bir nokta, sadece hashCode () geçersiz kılma hakkında . Tamamen iyi, değil mi? Veya sorunlu durumlar da olabilir mi?
Johnny

1
Bu yanıltıcı ve yanlış bir cevap. Geçersiz kılma (= only =) hashCode (), benzer özelliklere sahip ilgili sınıftan başlatılan her nesnenin aynı karma kodunu taşımasını sağlar. Ancak hiçbiri birbirine eşit olmayacağından faydalı olmayacaktır.
mfaisalhyder

8

Java bir kural koyar

"Object sınıfı eşittir yöntemi kullanılarak iki nesne eşitse, hashcode yöntemi bu iki nesne için aynı değeri vermelidir."

Yani, sınıfımızda geçersiz kılsak, bu kuralı takip etmek için yöntemi de equals()geçersiz hashcode()kılmalıyız. Her iki yöntem de, equals()ve hashcode(), kullanılan Hashtableanahtar değer çiftleri olarak değerleri depolamak için, örneğin,. Birini değil diğerini geçersiz kılarsak, Hashtableanahtar olarak bu nesneyi kullanırsak, istediğimiz gibi çalışmayabilir.


6

Çünkü bunları geçersiz kılmazsanız, Object içindeki varsayılan uygulamayı kullanacaksınız.

Eşitlik ve hascode değerlerinin genellikle bir nesneyi neyin oluşturduğuna dair bilgi gerektirdiği göz önüne alındığında, somut bir anlam elde etmek için sınıfınızda genellikle yeniden tanımlanması gerekecektir.


6

Kendi sınıf nesnelerimizi HashMap, Hashtable vb. Gibi koleksiyonlarda anahtar olarak kullanmak için, koleksiyonun dahili çalışması konusunda farkındalık yaratarak her iki yöntemi de (hashCode () ve equals ()) geçersiz kılmalıyız. Aksi takdirde, beklenmediğimiz yanlış sonuçlara yol açar.


6

@Lombo'nun cevabına ekleme

Eşittir () ne zaman geçersiz kılmanız gerekir?

Object equals () öğesinin varsayılan uygulaması:

public boolean equals(Object obj) {
        return (this == obj);
}

Bu, iki nesnenin yalnızca aynı bellek adresine sahip olmaları durumunda eşit kabul edileceği anlamına gelir; bu, yalnızca bir nesneyi kendisiyle karşılaştırmanız durumunda geçerli olacaktır.

Ancak, özelliklerinden biri veya daha fazlası için aynı değere sahiplerse, iki nesneyi aynı olarak değerlendirmek isteyebilirsiniz (@Lombo'nun cevabında verilen örneğe bakın).

Böylece equals()bu durumlarda geçersiz kılacaksınız ve eşitlik için kendi koşullarınızı vereceksiniz.

Eşittir () başarıyla uyguladım ve harika çalışıyor.Yani neden hashCode () geçersiz kılmak istiyorlar?

Kullanıcı tanımlı sınıfınızda "Hash" tabanlı Koleksiyonlar kullanmadığınız sürece sorun yok . Ama isteyebilirsiniz Gelecekte bir zamanda kullanmak HashMapveya HashSetsen değil yoksa overrideve hashCode () "doğru uygulamak" , bu Hash tabanlı tahsilat amaçlı değildir çalışması gibi.

Yalnızca geçersiz kılmaya eşittir (@Lombo'nun cevabına ek olarak)

myMap.put(first,someValue)
myMap.contains(second); --> But it should be the same since the key are the same.But returns false!!! How?

Her şeyden önce, HashMap hashCode secondöğesinin aynı olup olmadığını kontrol eder first. Yalnızca değerler aynı ise, aynı gruptaki eşitliği kontrol etmeye devam eder.

Ancak burada hashCode bu 2 nesne için farklıdır (çünkü varsayılan uygulamadan farklı bellek adresleri vardır). Dolayısıyla eşitliği kontrol etmek bile umursamaz.

Geçersiz kılınmış equals () yönteminizin içinde bir kesme noktanız varsa, farklı hashCodes'ları varsa içeri girmez. contains()kontrol eder hashCode()ve yalnızca aynı olmaları durumunda equals()yönteminizi çağırır .

Neden HashMap'in tüm kovalarda eşitliği kontrol etmesini sağlayamıyoruz? Bu yüzden hashCode () geçersiz kılmama gerek yok !!

O zaman Hash tabanlı koleksiyonların noktasını kaçırıyorsunuz. Aşağıdakileri göz önünde bulundur :

Your hashCode() implementation : intObject%9.

Aşağıdakiler, kova şeklinde saklanan anahtarlardır.

Bucket 1 : 1,10,19,... (in thousands)
Bucket 2 : 2,20,29...
Bucket 3 : 3,21,30,...
...

Diyelim ki, haritanın 10 anahtarını içerip içermediğini bilmek istiyorsunuz. Tüm bölümleri aramak ister misiniz? veya Yalnızca bir grup aramak ister misiniz?

HashCode'a dayanarak, 10 varsa, Bucket 1'de mevcut olması gerektiğini belirlersiniz. Bu yüzden yalnızca Bucket 1 aranacaktır !!


5
class A {
    int i;
    // Hashing Algorithm
    if even number return 0 else return 1
    // Equals Algorithm,
    if i = this.i return true else false
}
  • put ('anahtar', 'değer'), grubu hashCode()belirlemek için hash değerini hesaplar ve değerin Grupta equals()zaten mevcut olup olmadığını bulmak için yöntemi kullanır . Aksi takdirde eklenmezse mevcut değerle değiştirilir
  • get ('anahtar') hashCode()önce Girişi (grup) equals()bulmak ve Girişteki değeri bulmak için kullanılır

Her ikisi de geçersiz kılınmışsa,

<Map A >

Map.Entry 1 --> 1,3,5,...
Map.Entry 2 --> 2,4,6,...

eşittir geçersiz kılınmazsa

<Map A >

Map.Entry 1 --> 1,3,5,...,1,3,5,... // Duplicate values as equals not overridden
Map.Entry 2 --> 2,4,6,...,2,4,..

HashCode geçersiz kılınmazsa

<Map A >

Map.Entry 1 --> 1
Map.Entry 2 --> 2
Map.Entry 3 --> 3
Map.Entry 4 --> 1
Map.Entry 5 --> 2
Map.Entry 6 --> 3 // Same values are Stored in different hasCodes violates Contract 1
So on...

HashCode Eşit Sözleşme

  1. Eşit yönteme göre eşit iki anahtar aynı hashCode üretmelidir
  2. Aynı hashCode üreten iki Anahtarın eşit olması gerekmez (Yukarıdaki örnekte tüm çift sayılar aynı karma Kodu oluşturur)

4

Siyah renkte bir kova topları toplamayı düşünün. İşiniz bu topları aşağıdaki gibi renklendirmek ve uygun oyun için kullanmaktır,

Tenis için - Sarı, Kırmızı. Kriket İçin - Beyaz

Şimdi kova üç renk Sarı, Kırmızı ve Beyaz toplar var. Ve şimdi renklendirme yaptın Sadece hangi oyunun hangi rengin olduğunu biliyorsun.

Topları Boyama - Hashing. Oyun için top seçimi - Eşittir.

Eğer renklendirme yaptıysanız ve bazıları topu kriket ya da tenis için seçtiyse rengi önemsemezler !!!


4

"Eğer hashCode'u geçersiz kıldığınızda o zaman myMap.put(first,someValue)ilk çağırdığınızda , hashCode'unu hesaplar ve belirli bir kovada saklarsanız, daha sonra çağırdığınızda myMap.put(first,someOtherValue)Eşit oldukları için Harita Belgelerine göre ikinci ile değiştirilmelidir. (tanımımıza göre). " :

Sanırım eklediğimizde 2. kez myMapo zaman 'ikinci' nesne olmalımyMap.put(second,someOtherValue)


4

1) Yaygın hata aşağıdaki örnekte gösterilmiştir.

public class Car {

    private String color;

    public Car(String color) {
        this.color = color;
    }

    public boolean equals(Object obj) {
        if(obj==null) return false;
        if (!(obj instanceof Car))
            return false;   
        if (obj == this)
            return true;
        return this.color.equals(((Car) obj).color);
    }

    public static void main(String[] args) {
        Car a1 = new Car("green");
        Car a2 = new Car("red");

        //hashMap stores Car type and its quantity
        HashMap<Car, Integer> m = new HashMap<Car, Integer>();
        m.put(a1, 10);
        m.put(a2, 20);
        System.out.println(m.get(new Car("green")));
    }
}

yeşil Araba bulunamadı

2. hashCode () öğesinin neden olduğu sorun

Sorun geçersiz kılınan yöntemden kaynaklanır hashCode(). Arasındaki sözleşme equals()ve hashCode()geçerli:

  1. İki nesne eşitse, aynı karma koduna sahip olmaları gerekir.
  2. İki nesne aynı karma koduna sahipse, bunlar eşit olabilir veya olmayabilir.

    public int hashCode(){  
      return this.color.hashCode(); 
    }

4

Değer Nesneleri kullanılırken yararlıdır . Aşağıdaki Portland Desen Deposundan bir alıntıdır :

Değer nesnelerine örnek olarak sayılar, tarihler, paralar ve karakter dizileri verilebilir. Genellikle, oldukça yaygın olarak kullanılan küçük nesnelerdir. Kimlikleri, nesne kimlikleri yerine devletlerine dayanmaktadır. Bu şekilde, aynı kavramsal değer nesnesinin birden çok kopyasına sahip olabilirsiniz.

Dolayısıyla, 16 Ocak 1998 tarihini temsil eden bir nesnenin birden fazla kopyasına sahip olabilirim. Bu kopyalardan herhangi biri birbirine eşit olacaktır. Bunun gibi küçük bir nesne için, tarihi temsil etmek için tek bir nesneye güvenmek yerine yenilerini oluşturmak ve hareket ettirmek genellikle daha kolaydır.

Bir değer nesnesi her zaman Java'da .equals () değerini geçersiz kılar (veya Smalltalk içinde =). (.HashCode () işlevini de geçersiz kılmayı unutmayın.)


3

Diğer iki (B) (C) birleştiren (A) sınıfınız olduğunu ve (A) örneklerini hashtable içinde saklamanız gerektiğini varsayalım. Varsayılan uygulama yalnızca örneklerin ayırt edilmesine izin verir, ancak (B) ve (C) ile ayrılmaz. Dolayısıyla, iki A örneği eşit olabilir, ancak varsayılan, bunları doğru şekilde karşılaştırmanıza izin vermez.


3

Eşittir ve hashcode yöntemleri nesne sınıfında tanımlanır. Varsayılan olarak equals yöntemi true değerini döndürürse, sistem daha ileri gider ve karma kodunun değerini kontrol eder. 2 nesnenin karma kodu da sadece aynı ise, nesneler aynı kabul edilir. Bu nedenle, yalnızca eşittir yöntemini geçersiz kılarsanız, geçersiz kılınmış eşittir yöntemi 2 nesnenin eşit olduğunu gösterse de, sistem tanımlı karma kodu 2 nesnenin eşit olduğunu göstermeyebilir. Bu yüzden karma kodunu da geçersiz kılmamız gerekiyor.


Equals yöntemi true değerini döndürürse, hashcode'u kontrol etmeye gerek yoktur. Bununla birlikte, iki nesnenin farklı hashcode'ları varsa, eşit çağırmak zorunda kalmadan bunları farklı olarak kabul edebilmelidir. Ayrıca, listedeki hiçbir şeyin belirli bir karma kodu olmadığını bilmek, listedeki hiçbir şeyin nay nesnesiyle bu karma kodunu eşleştiremeyeceğini ima eder. Basit bir örnek olarak, bir kişinin karma kodları çift sayı olan nesnelerin bir listesi ve tek sayı olan nesnelerin bir listesi varsa, karma kodu çift sayı olan hiçbir nesne ikinci listede bulunmaz.
supercat

Birinde "eşittir" yöntemlerinin eşleştiğini belirten iki X ve Y nesnesi varsa, ancak X'un karma kodu çift bir sayı ve Y'nin karma kodu tek bir sayıysa, yukarıda açıklandığı gibi Y nesnesinin karma kodunun garip olduğunu ve saklandığını belirten bir koleksiyon ikinci listede X nesnesi için bir eşleşme bulamaz. X'in karma kodunun eşit olduğunu gözlemlerdi ve ikinci listede çift numaralı karma kodları olan herhangi bir nesne olmadığı için rahatsız olmaz orada X ile eşleşen bir şey aramak için, Y X ile eşleşse bile.
Söylemelisin

... birçok koleksiyon, karma kodları eşit olamayacaklarını ima eden şeyleri karşılaştırmaktan kaçınacaktır. Kimin karma kodları bilinmediği iki nesne göz önüne alındığında, bu yüzden eşit olmayan karma kodları ama dönüşü rapor şeyler hiçbir garantisi yoktur, hesaplama daha doğrudan karma kodları bunları karşılaştırmak çoğu zaman hızlıdır trueiçin equalseşleştirme olarak kabul edilmeyecektir. Öte yandan, koleksiyonlar gerçekleşirse, işlerin aynı karma koduna sahip olamayacağını fark ederse, muhtemelen eşit olduklarını fark etmeyeceklerdir.
supercat

3

Java'da Eşittir ve Hashcode yöntemleri

Bunlar, tüm sınıfların süper sınıfı olan java.lang.Object sınıfının yöntemleridir (özel sınıflar ve java API'sinde tanımlanan diğerleri).

Uygulama:

genel boole eşittir (Object obj)

public int hashCode ()

resim açıklamasını buraya girin

genel boole eşittir (Object obj)

Bu yöntem, iki nesnenin x ve y ile aynı nesneye gönderme yapıp yapmadığını kontrol eder. ie x == y olup olmadığını kontrol eder.

Dönüşlüdür : x herhangi bir referans değeri için x.equals (x) doğru dönmelidir.

Simetriktir: x ve y referans değerleri için x.equals (y), yalnızca y.equals (x) true değerini döndürürse true değerini döndürmelidir.

Geçişlidir : x, y ve z referans değerleri için, x.equals (y) true değerini ve y.equals (z) true değerini döndürüyorsa, x.equals (z) true değerini döndürmelidir.

Tutarlıdır : x ve y referans değerleri için, x.equals (y) 'nin çoklu çağrılması, nesne üzerinde eşit karşılaştırmalarda kullanılan hiçbir bilgi değiştirilmediği sürece, sürekli olarak true değerini döndürür veya sürekli olarak false değerini döndürür.

Null olmayan tüm referans değerleri için x, x.equals (null) false döndürmelidir.

public int hashCode ()

Bu yöntem, bu yöntemin çağrıldığı nesne için karma kod değerini döndürür. Bu yöntem, karma kodu değerini bir tamsayı olarak döndürür ve Hashtable, HashMap, HashSet vb. Gibi karma tabanlı toplama sınıflarının yararına desteklenir. Bu yöntem, equals yöntemini geçersiz kılan her sınıfta geçersiz kılınmalıdır.

HashCode'un genel sözleşmesi:

Bir Java uygulamasının yürütülmesi sırasında aynı nesneye birden çok kez çağrıldığında, nesne üzerinde eşit karşılaştırmalarda kullanılan hiçbir bilgi değiştirilmediği sürece hashCode yönteminin sürekli olarak aynı tamsayıyı döndürmesi gerekir.

Bu tamsayı, bir uygulamanın bir uygulamasından aynı uygulamanın başka bir uygulamasına kadar tutarlı kalmasına gerek yoktur.

İki nesne eşittir (Object) yöntemine göre eşitse, iki nesnenin her birinde hashCode yönteminin çağrılması aynı tamsayı sonucunu üretmelidir.

Eşittir (java.lang.Object) yöntemine göre iki nesne eşit değilse, iki nesnenin her birinde hashCode yönteminin çağrılmasının farklı tamsayı sonuçları üretmesi gerekmez. Bununla birlikte, programcı eşit olmayan nesneler için farklı tamsayı sonuçları üretmenin hashtable'ların performansını artırabileceğinin farkında olmalıdır.

Eşit nesneler, eşit oldukları sürece aynı karma kodunu üretmelidir, ancak eşit olmayan nesnelerin farklı karma kodları üretmesi gerekmez.

Kaynaklar:

Javaranch

Resim


Resim (video bağlantısı) özel modda. İzlemeyi herkese açık yapın.
Uday Kiran Pulipati

2

Aşağıdaki örnekte, Person sınıfındaki eşittir veya hashcode için geçersiz kılma yorumunu yaparsanız, bu kod Tom'un sırasını arayamaz. Varsayılan hashcode uygulamasını kullanmak, hashtable aramaları sırasında hatalara neden olabilir.

Aşağıda ne var Kişi tarafından insanların sırasını çeker basitleştirilmiş bir kod. Kişi hashtable içinde bir anahtar olarak kullanılıyor.

public class Person {
    String name;
    int age;
    String socialSecurityNumber;

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

    @Override
    public boolean equals(Object p) {
        //Person is same if social security number is same

        if ((p instanceof Person) && this.socialSecurityNumber.equals(((Person) p).socialSecurityNumber)) {
            return true;
        } else {
            return false;
        }

    }

    @Override
    public int hashCode() {        //I am using a hashing function in String.java instead of writing my own.
        return socialSecurityNumber.hashCode();
    }
}


public class Order {
    String[]  items;

    public void insertOrder(String[]  items)
    {
        this.items=items;
    }

}



import java.util.Hashtable;

public class Main {

    public static void main(String[] args) {

       Person p1=new Person("Tom",32,"548-56-4412");
        Person p2=new Person("Jerry",60,"456-74-4125");
        Person p3=new Person("Sherry",38,"418-55-1235");

        Order order1=new Order();
        order1.insertOrder(new String[]{"mouse","car charger"});

        Order order2=new Order();
        order2.insertOrder(new String[]{"Multi vitamin"});

        Order order3=new Order();
        order3.insertOrder(new String[]{"handbag", "iPod"});

        Hashtable<Person,Order> hashtable=new Hashtable<Person,Order>();
        hashtable.put(p1,order1);
        hashtable.put(p2,order2);
        hashtable.put(p3,order3);

       //The line below will fail if Person class does not override hashCode()
       Order tomOrder= hashtable.get(new Person("Tom", 32, "548-56-4412"));
        for(String item:tomOrder.items)
        {
            System.out.println(item);
        }
    }
}

2

String sınıfı ve wrapper sınıfları, Object sınıfından farklı uygulama equals()ve hashCode()yöntemlere sahiptir. Object sınıfının equals () yöntemi, nesnelerin içeriklerini değil referanslarını karşılaştırır. Object sınıfının hashCode () yöntemi, içeriklerin aynı olup olmadığına bakılmaksızın her bir nesne için farklı bir hashcode döndürür.

Harita koleksiyonunu kullandığınızda soruna yol açar ve anahtar Kalıcı türde, StringBuffer / builder türündedir. String sınıfından farklı olarak equals () ve hashCode () öğelerini geçersiz kılmadığından, her ikisi de aynı içeriğe sahip olsa bile iki farklı nesneyi karşılaştırdığınızda equals () işlevi false değerini döndürür. HashMap'in aynı içerik anahtarlarını depolamasını sağlar. Aynı içerik anahtarlarını depolamak, Harita'nın yinelenen anahtarlara izin vermediği için Harita kuralını ihlal ettiği anlamına gelir. Bu nedenle, sınıfınızda eşittir () ve hashCode () yöntemlerini geçersiz kılar ve uygulamayı sağlarsınız (IDE bu yöntemleri oluşturabilir), böylece String'in equals () ve hashCode () ile aynı şekilde çalışır ve aynı içerik anahtarlarını engeller.

Equals () ile birlikte hashCode () yöntemini geçersiz kılmanız gerekir, çünkü equals () hashcode'a göre çalışır.

Ayrıca equals () ile birlikte hashCode () yönteminin geçersiz kılınması equals () - hashCode () sözleşmesinin bozulmasına yardımcı olur: "İki nesne eşitse, aynı karma koduna sahip olmalıdır."

HashCode () için ne zaman özel uygulama yazmanız gerekir?

Bildiğimiz gibi HashMap'in dahili çalışmasının Hashing prensibi olduğunu. Entrysetlerin depolandığı bazı kovalar vardır. Aynı kategori nesnelerinin aynı dizine depolanabilmesi için hashCode () uygulamasını gereksiniminize göre özelleştirirsiniz. değerleri put(k,v)yöntemi kullanarak Harita koleksiyonuna kaydettiğinizde , put () yönteminin iç uygulaması:

put(k, v){
hash(k);
index=hash & (n-1);
}

Yani, dizin üretir ve dizin belirli anahtar nesnenin hashcode'u temelinde oluşturulur. Bu nedenle, aynı hashcode entrysets aynı kova veya indekste saklanacağından, bu yöntemi gereksiniminize göre hashcode üretin.

Bu kadar!


1

hashCode()yöntemi, belirli bir nesne için benzersiz bir tam sayı elde etmek için kullanılır. Bu tam sayı bu amaç, bir depolanacak gerektiğinde, kepçe konumunun saptanması için kullanılır HashTable, HashMapveri yapısı gibi. Varsayılan olarak, Object hashCode()yöntemi döndürülür ve nesnenin depolandığı bellek adresinin tamsayı temsili.

hashCode()Nesneleri gibi bir yöntem bir içine eklemek zaman kullanılan HashTable, HashMapveya HashSet. HashTablesReferans için Wikipedia.org hakkında daha fazla bilgi .

Harita veri yapısına herhangi bir girdi eklemek için hem anahtar hem de değere ihtiyacımız var. Hem anahtar hem de değerler kullanıcı tanımlı veri türüyse, hashCode()anahtarın nesnenin dahili olarak nerede saklanacağı belirlenir. Nesneyi haritadan da aramak gerektiğinde, anahtarın karma kodu, nesnenin nerede aranacağını belirler.

Karma kodu yalnızca dahili olarak belirli bir "alanı" (veya liste, grup vb.) Gösterir. Farklı anahtar nesneler potansiyel olarak aynı karma koduna sahip olabileceğinden, karma kodun kendisi doğru anahtarın bulunacağının garantisi değildir. Ardından HashTablebu alanı tekrarlar (aynı karma koduna sahip tüm anahtarlar) ve equals()doğru anahtarı bulmak için anahtarın yöntemini kullanır . Sağ anahtar bulunduğunda, o anahtar için depolanan nesne döndürülür.

Gördüğümüz gibi, bir nesneyi saklarken ve ararken bir hashCode()ve equals()yöntemlerinin birleşimi kullanılır HashTable.

NOTLAR:

  1. Nesnenin her zaman aynı niteliklerini hashCode()ve equals()her ikisini birden kullanın. Bizim durumumuzda olduğu gibi, çalışan kimliği kullandık.

  2. equals() tutarlı olmalıdır (nesneler değiştirilmediyse, aynı değeri döndürmeye devam etmelidir).

  3. Ne zaman olursa a.equals(b), o a.hashCode()zaman aynı olmalıdır b.hashCode().

  4. Birini geçersiz kılarsanız, diğerini geçersiz kılmalısınız.

http://parameshk.blogspot.in/2014/10/examples-of-comparable-comporator.html


hashCode()her nesne için benzersiz bir tamsayı döndürmek için kullanılmaz. İmkansız. Dördüncü paragrafın ikinci cümlesinde kendinizle çeliştiniz.
Lorne Marquis

@EJP, çoğu zaman hascode () iki farklı nesne için benzersiz bir interger döndürür. Ancak iki farklı nesne için çarpışma hascode'u olasılığı vardır, bu kavram Hashcode Çarpışma olarak adlandırılır . Lütfen bakınız: tech.queryhome.com/96931/…
Paramesh Korrakuti

1

IMHO, kurallara göre - İki nesne eşitse, aynı karma değerine sahip olmalıdır, yani eşit nesneler eşit karma değerler üretmelidir.

Yukarıda verildiği gibi, Object içindeki varsayılan equals () == adresidir ve adres üzerinde karşılaştırma yapar, hashCode () adresi tamsayıda (gerçek adres üzerinde hash) döndürür ve bu da farklı Object için ayrıdır.

Karma tabanlı koleksiyonlarda özel Nesneleri kullanmanız gerekiyorsa, hem equals () hem de hashCode () öğelerini geçersiz kılmanız gerekir, örneğin Çalışan Nesnelerin HashSet'ini korumak istiyorsanız, daha güçlü hashCode ve eşitlerini kullanmıyorsam İki farklı Çalışan Nesneleri geçersiz kılmaya devam edebilirim, bu hashCode () olarak yaşı kullandığımda olur, ancak Çalışan Kimliği olabilecek benzersiz değeri kullanmalıyım.


1

Yinelenen Nesneleri kontrol etmenize yardımcı olmak için özel bir eşittir ve hashCode gerekir.

Hashcode her zaman bir sayı döndürdüğünden, alfabetik bir anahtar yerine bir sayı kullanarak bir nesneyi almak her zaman hızlıdır. Nasıl olacak? Başka bir nesnede zaten mevcut olan bir değeri geçirerek yeni bir nesne oluşturduğumuzu varsayalım. Şimdi yeni nesne, aktarılan değer aynı olduğundan başka bir nesneyle aynı hash değerini döndürecektir. Aynı karma değeri döndürüldüğünde, JVM her seferinde aynı bellek adresine gider ve aynı karma değeri için birden fazla nesne olması durumunda, doğru nesneyi tanımlamak için equals () yöntemini kullanır.


1

Özel nesnenizi Harita'da bir anahtar olarak depolamak ve almak istediğinizde, özel Nesnenizde her zaman eşittir ve hashCode'u geçersiz kılmalısınız. Örneğin:

Person p1 = new Person("A",23);
Person p2 = new Person("A",23);
HashMap map = new HashMap();
map.put(p1,"value 1");
map.put(p2,"value 2");

Burada p1 ve p2, tek bir nesne olarak kabul edilir ve mapeşit oldukları için boyut sadece 1 olacaktır.


1
public class Employee {

    private int empId;
    private String empName;

    public Employee(int empId, String empName) {
        super();
        this.empId = empId;
        this.empName = empName;
    }

    public int getEmpId() {
        return empId;
    }

    public void setEmpId(int empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    @Override
    public String toString() {
        return "Employee [empId=" + empId + ", empName=" + empName + "]";
    }

    @Override
    public int hashCode() {
        return empId + empName.hashCode();
    }

    @Override
    public boolean equals(Object obj) {

        if (this == obj) {
            return true;
        }
        if (!(this instanceof Employee)) {
            return false;
        }
        Employee emp = (Employee) obj;
        return this.getEmpId() == emp.getEmpId() && this.getEmpName().equals(emp.getEmpName());
    }

}

Test Sınıfı

public class Test {

    public static void main(String[] args) {
        Employee emp1 = new Employee(101,"Manash");
        Employee emp2 = new Employee(101,"Manash");
        Employee emp3 = new Employee(103,"Ranjan");
        System.out.println(emp1.hashCode());
        System.out.println(emp2.hashCode());
        System.out.println(emp1.equals(emp2));
        System.out.println(emp1.equals(emp3));
    }

}

Nesne Sınıfı eşittir (Object obj) adres karşılaştırmasını karşılaştırmak için kullanılır, bu yüzden Test sınıfında iki nesneyi karşılaştırırsanız, yanlış veren yöntem eşittir, ancak hashcode () geçersiz kıldığımızda içeriği karşılaştırabilir ve doğru sonuç verebilir.


ve Test programı I aşağıdaki programa eklendi.
Manash Ranjan Dakua

Nesne Sınıfı eşittir (Object obj) adres karşılaştırmasını karşılaştırmak için kullanılır, bu yüzden Test sınıfında iki nesneyi karşılaştırırsanız, yanlış veren yöntem eşittir, ancak hashcode () geçersiz kıldığımızda içeriği karşılaştırabilir ve doğru sonuç verebilir.
Manash Ranjan Dakua

1
cevabınıza eklemek için bu cevabın hemen altındaki düzenleme bağlantısını kullanabilirsiniz .. Lütfen
Suraj Rao

1

Geçersiz kılsanız equals()ve yapmazsanız hashcode(), siz veya bir başkası bu sınıf türünü karma bir koleksiyonda kullanmadığı sürece herhangi bir sorun bulamazsınız HashSet. Önümde olan kişiler, belgelenmiş teoriyi birçok kez açık bir şekilde açıkladı, ben sadece çok basit bir örnek sunmak için buradayım.

equals()Özelleştirilmiş bir şey ifade etme ihtiyacı olan bir sınıfı düşünün :

    public class Rishav {

        private String rshv;

        public Rishav(String rshv) {
            this.rshv = rshv;
        }

        /**
        * @return the rshv
        */
        public String getRshv() {
            return rshv;
        }

        /**
        * @param rshv the rshv to set
        */
        public void setRshv(String rshv) {
            this.rshv = rshv;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof Rishav) {
                obj = (Rishav) obj;
                if (this.rshv.equals(((Rishav) obj).getRshv())) {
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }

        @Override
        public int hashCode() {
            return rshv.hashCode();
        }

    }

Şimdi bu ana sınıfı düşünün:

    import java.util.HashSet;
    import java.util.Set;

    public class TestRishav {

        public static void main(String[] args) {
            Rishav rA = new Rishav("rishav");
            Rishav rB = new Rishav("rishav");
            System.out.println(rA.equals(rB));
            System.out.println("-----------------------------------");

            Set<Rishav> hashed = new HashSet<>();
            hashed.add(rA);
            System.out.println(hashed.contains(rB));
            System.out.println("-----------------------------------");

            hashed.add(rB);
            System.out.println(hashed.size());
        }

    }

Bu, aşağıdaki çıktıyı verecektir: -

    true
    -----------------------------------
    true
    -----------------------------------
    1

Sonuçlardan memnunum. Ancak hashCode(), geçersiz kılmamışsam , Rishavaynı üye içeriğine sahip nesneler artık hashCodevarsayılan davranış tarafından oluşturulduğu gibi farklı olacak gibi benzersiz olarak değerlendirilmeyeceğinden kabusa neden olacaktır: İşte çıktı: -

    true
    -----------------------------------
    false
    -----------------------------------
    2

0

Her iki yöntem de Object sınıfında tanımlanır. Ve her ikisi de en basit uygulamasında. Yani ihtiyacınız olduğunda bu yöntemlere biraz daha fazla uygulama eklemek istediğinizde sınıfınızda geçersiz kılmanız gerekir.

Örnekteki ex: equals () yöntemi yalnızca referanstaki eşitliğini kontrol eder. Durumunu da karşılaştırmanız gerekiyorsa, String sınıfında olduğu gibi bunu geçersiz kılabilirsiniz.


-3

Bah - "Eşittir () öğesini geçersiz kılan her sınıfta hashCode () yöntemini geçersiz kılmalısınız."

[Etkili Java'dan, Joshua Bloch tarafından mı?]

Bu yanlış bir yol değil mi? HashCode'un geçersiz kılınması büyük olasılıkla bir karma anahtar sınıfı yazdığınızı ima eder, ancak geçersiz kılma kesinlikle olmaz. Karma anahtar olarak kullanılmayan, ancak başka bir nedenden ötürü mantıksal eşitlik testi yöntemi isteyen birçok sınıf vardır. Bunun için "eşittir" i seçerseniz, bu kuralın aşırı derecede uygulanmasıyla bir hashCode uygulaması yazma yetkiniz olabilir. Bütün başarıları kod tabanına denenmemiş kod eklemek, gelecekte birini selamlamak için kötü bir şey bekliyor. Ayrıca ihtiyacınız olmayan kod yazmak anti-agile. Bu sadece yanlış (ve üretilen bir ide muhtemelen el yapımı eşitlerinizle uyumsuz olacaktır).

Şüphesiz, anahtar olarak kullanılmak üzere yazılmış nesneler için bir Arayüz zorunlu kılmalıydılar? Ne olursa olsun, Object asla varsayılan hashCode () ve equals () imho değerini sağlamamalıdır. Muhtemelen birçok kırık karma koleksiyonunu teşvik ediyor.

Ama neyse, bence "kural" önden yazılıyor. Bu arada, eşitlik testi yöntemleri için "eşittir" kullanmaktan kaçınmaya devam edeceğim :-(

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.