• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

C# - dlaczego metoda GetHashCode jest tak ważna?

Object Storage Arubacloud
0 głosów
1,244 wizyt
pytanie zadane 18 stycznia 2020 w C# przez dawid2002 Mądrala (5,190 p.)
Witam! Prześledziłem internet w celu odpowiedzi czemu, gdy przesłaniamy metodę Equals to trzeba też przesłonić GetHashCode? Ponoć tą drugą stosuje się w tablicach skrótów, jakimi są Dictionary<,> oraz Hashtable i powinno się odpowiednio przesłonić GetHashCode aby wartość skrótu dla kluczy się nie powtarzała, ale dlaczego nie może się powtórzyć?

1 odpowiedź

+1 głos
odpowiedź 18 stycznia 2020 przez k222 Nałogowiec (30,150 p.)
wybrane 18 stycznia 2020 przez dawid2002
 
Najlepsza

czemu, gdy przesłaniamy metodę Equals to trzeba też przesłonić GetHashCode?

To jest ogólna zasada, nie ważne czy piszesz w C#, Javie, C++, czy czymś innym. Chodzi właśnie o wszelkie struktury używające hash'y  typu hashset, hashtable, dictionary / map (w różnych językach różnie się nazywają).

Generalnie istnieje konwencja, że jeśli equals zwraca true, to generowany hashCode dla dwóch obiektów powinien być identyczny. W przeciwnym wypadku dwa obiekty, dla których equals zwraca true, mogą zostać dodane do takiej struktury, bo generowany hashCode będzie różny. Może to powodować w przyszłości duże problemy i ciężkie do znalezienia błędy dla kogoś kto użyłby twojego kodu (lub dla ciebie po długim czasie), typu problem z wyciąganiem obiektu. Mam nawet przykład (niestety w Javie, ale na tyle prosty że zrozumiesz). Powiedz mi co wypiszą dwa System.out.println na dole?

import java.util.HashMap;

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(a1));
        System.out.println(m.get(new Car("green")));
    }
}

Możesz sobie to uruchomić TUTAJ, Zauważ, że metoda m.get(a1) zwraca obiekt, a metoda m.get(new Car("green") zwraca null. No i mamy problem, bo w większej aplikacji nie z każdego miejsca będziesz miał dostęp do zmiennej a1 żeby sobie nią wyciągnąć obiekt z mapy.  Zeby rozwiązać ten problem wystarczy do klasy Car dodać coś w stylu:

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

 

Jako anegdota dodam, że przesłanianie hashCode() bez przesłaniania equals() też jest zdecydowanie nie wskazane, ale  dobra metoda hashCode zapewni poprawne działanie wszelkich struktur używających hash'y, problem będziesz miał jedynie ze stwierdzeniem, czy dwa obiekty są równe.

 

powinno się odpowiednio przesłonić GetHashCode aby wartość skrótu dla kluczy się nie powtarzała, ale dlaczego nie może się powtórzyć?

To już inna kwestia, po prostu struktura typu hashTable bierze obiekt, liczy dla niego hash i dodaje obiekt odwołując się do niego przez ten wygenerowany hash. Jeżeli obiekty o1 i o2 będą miały ten sam hashCode i dodasz najpierw o1, potem o2 to o2 zostanie wstawione w miejsce o1,.o1 po prostu zniknie. Aby uniknąć takiej sytuacji, najlepiej jest robić jakieś mocno unikalne hashe (np. jak masz produkt w sklepie jako obiekt, to zwracanie jego ceny jako hashu jest złym pomysłem, bo ceny mogą się powtarzać.

komentarz 18 stycznia 2020 przez dawid2002 Mądrala (5,190 p.)

Dzięki yes

komentarz 18 stycznia 2020 przez dawid2002 Mądrala (5,190 p.)

@k222, Przepraszam czy mógłbyś znaleźć jakiś podobny przykład, ale w C#. Bo w Javie wszystko jest jasne, ale gdy próbowałem to zrobić w C# to wychodziły mi dziwne wyniki. Gdy użyłem Dictionary to nie ważne czy hash był inny czy taki sam dla każdego obiektu to wszystko poprawnie działało, zaś w przypadku Hashtable wszystko było dobrze, gdy hashe były inne (nawet dla tych samych elementów).

Podobne pytania

0 głosów
0 odpowiedzi 122 wizyt
+11 głosów
3 odpowiedzi 565 wizyt
+1 głos
2 odpowiedzi 503 wizyt
pytanie zadane 10 stycznia 2020 w C# przez dawid2002 Mądrala (5,190 p.)

92,536 zapytań

141,377 odpowiedzi

319,456 komentarzy

61,922 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...