2012-02-24 14 views
5

Dlaczego istnieją różne wartości parametru hashCode dla każdego uruchomienia głównej wersji Java? Sprawdź przykładowy kod poniżej.Różne generowanie kodu Enum HashCode?

interface testInt{ 

    public int getValue(); 
} 

enum test implements testInt{ 
    A(1), 
    B(2); 

    private int value; 

    private test(int value) { 
     this.value = value; 
    } 

    public int getValue() { 
     return this.value; 
    } 
} 

Na każdym uruchomieniu,

public static void main(String[] args) { 
    System.out.println(test.A.hashCode()); 
} 

będą drukowane różne wartości na konsoli. Dlaczego ta niespójność?

Odpowiedz

3

Jeśli chcesz mieć tę samą wartość za każdym razem, użyj .ordinal() lub nawet lepiej, użyj getValue(), tak jak masz. Można nadpisać wartość hashCode() od wartości domyślnej, która ma nadać jej numer, który jest oparty na sposobie utworzenia obiektu.

+0

Tak, używam teraz getValue jako rozwiązanie. Właśnie utworzyłem post, aby zobaczyć, dlaczego różne hashCodes przy wdrażaniu interfejsu. Dzięki. –

2

Jawadoki wyraźnie to stwierdzają. Z Javadocs dla metody kodów skrótu w obiekcie c klasy

O ile jest to uzasadnione i praktyczny sposób hashCode określa klasa obiektu nie powraca różne liczby całkowite dla różnych przedmiotów. (Jest to zwykle realizowane poprzez konwersję adresu wewnętrznego obiektu na liczbę całkowitą, ale ta technika implementacji nie jest wymagana przez język programowania JavaTM.)

Tak więc w różnych przebiegach kodu demonstracyjnego adres wewnętrzny może różnić się, a więc jest zupełnie normalne, aby zobaczyć różne wartości.

W zależności od potrzeb, jeśli chcesz, aby metoda hashcode() zwracała tę samą wartość dla wywołań jvm, należy zastąpić metodę, aby zwrócić wartość niestandardową. Jednak powinieneś wiedzieć, że może to być katastrofalne, jeśli obiekt ma być używany w kolekcjach opartych na hashach (zwiększone szanse na kolizję hash).

+0

Jak już powiedziałem. To, co przywiodło mnie tutaj, to fakt, proste wyliczenie, w mojej Oracle JVM7, zwracał ten sam hashCode w różnych seriach. Ale po zamianie na wyspecjalizowaną enum, hashcode był inny dla każdego uruchomienia. –

3

"Nie ma wymogu, aby wartości mieszania były spójne między różnymi implementacjami Javy, a nawet pomiędzy różnymi przebiegami wykonawczymi tego samego programu."

http://en.wikipedia.org/wiki/Java_hashCode%28%29

http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Object.html#hashCode%28%29

public static void main(String[] args) { 
    System.out.println(test.A.hashCode()); 
    System.out.println(test.A.hashCode()); 
} 

Kod ten będzie teraz produkować sam hashCode.

+0

OK, ale dzieje się tak tylko, jeśli masz wyliczenie, które implementuje interfejs. –

+0

Niekoniecznie. Jeśli porównujesz z tworzeniem hashcode ciągu znaków (lub czegoś innego) pomiędzy wykonaniem programu, fakt, że generują ten sam kod może być zbiegiem okoliczności. – jn1kk

+0

Zgaduję, że zbieg okoliczności nie jest właściwym słowem. To naprawdę zwraca tę samą wartość hashCode dla wyliczeń, które nie implementują żadnego interfejsu. To właśnie wskazało mi tutaj. –

0

Być może niektóre implementacje JVM w zasadzie zwracają Enum.ordinal() (co również byłoby wspaniałe hashCode) - ale to niczego nie zmieni skutecznie. Wartość hashCode() nie musi być spójna dla wszystkich wykonań lub maszyn JVM. Jedyny wymagany kontrakt opisany jest w JavaDocs of Object.hashCode() - i jest to implementacja w Object, która jest używana w enum.

Należy również pamiętać, że wdrożenie interfejsu nie ma nic wspólnego z hashCode():

public class TestEnum { 

    public static void main(String[] args) { 
     System.out.println(Silly.B.hashCode()); 
     System.out.println(Silly.C.hashCode()); 
     System.out.println(Silly.D.hashCode()); 
    } 
} 

enum Silly { 
    B, C, D 
} 

Program ten zwraca również różne hashCode() s na każdym biegu.

+0

Ok, Silly.B.hashCode, zwróci te same i nie różne kody. Jeśli implementacja interfejsu nie ma nic wspólnego z hashCode, dlaczego tak się dzieje? Czy widzisz, dokąd idę? Silly.B.hashCode jest równy dla różnych przebiegów, ale jeśli utwórz Silly implementuje prosty interfejs, to będą różne kody hash dla Silly.A –

+0

@ VíctorHugo: którego JVM używasz? W wersji 1.6.0_26-b03 czasami zwraca te same, a czasem inne wartości, ale z pewnością nie są one takie same przez cały czas ... –

+0

JVM, jdk1.7.0_02 (Oracle) –

0

Enum.hashCode nie jest zdefiniowany, aby zwracać określone wartości (inne niż przestrzeganie zasad Object.hashCode), a wspólne implementacje nie robią nic specjalnego.

Dlaczego? Jeśli używasz wyliczeń (tylko) w HashSet lub jako klucz w HashMap, powinieneś zamiast tego używać zoptymalizowanego EnumSet lub EnumMap. Teraz zastanów się, czy enum miał być używany wraz z innymi typami w HashSet. Być może masz jakieś "standardowe opcje" do implementacji interfejsu, ale inne mogą mieć własne opcje. Wszystko, co zrobi bezpaństwowiec. Wiele typów wyliczeniowych w jednym HashSet. Jeśli Enum użył liczb porządkowych dla wartości mieszania, wówczas będziesz mieć wspólne kolizje. Korzystanie z System.identityHashCode redukuje kolizje w niezawodny sposób.

public interface Option { 
} 
public enum StandardOptions implements Option { 
    A, B, C 
} 
enum CustomOptions { 
    P, Q, R 
} 
enum MoreOptions { 
    X, Y, Z 
} 

    Set<Option> options = new HashSet<>(); 
    options.add(A); 
    options.add(P); 
    options.add(X); 

Naprawdę nie chcemy A.hashCode() == P.hashCode() == X.hashCode().