Хаш кодът на Java низ независим ли е от локала?

Е Java String.hashcode() напълно независимо от Locale? С други думи, ако някой си играе с Locale по подразбиране, дали сме 100% сигурни, че това няма да повлияе на хеш кода?

Знаем, че подобно бъркотене влияе върху toUpperCase() и toLowerCase().


person Jérôme Verstrynge    schedule 27.08.2011    source източник
comment
Възможен дубликат: stackoverflow.com/ въпроси/785091/   -  person Bryan Menard    schedule 28.08.2011
comment
@Bryan Видях този въпрос, но той не отговаря на проблема, който повдигам.   -  person Jérôme Verstrynge    schedule 28.08.2011


Отговори (4)


Локалът не засяга хеш-кода на низа (директно). Той се основава единствено на знаците, съхранени в низа. Хеш-кодът се генерира от

char[] val;

for (int i = 0; i < len; i++) {
    h = 31*h + val[off++];
}

но проблемът е как се генерира низът. Ако това е, например, резултатът от toUpperCase, който зависи от Locale, очевидно полученият String зависи от Locale, както и hashCode.

person user85421    schedule 28.08.2011

Добър въпрос, проведох бърз тест и изглежда, че промяната на локала по подразбиране не променя (за щастие) хеш кода ...

import java.util.Locale;

public class HashCodeTester {

    public static void main(String[] args) {

        String test = "test";
        int hashCode = test.hashCode();

        System.out.println("hashcode [" + hashCode + "] - locale [" + Locale.getDefault() + "]");

        Locale[] availableLocales = Locale.getAvailableLocales();
        for(int i=0; i<availableLocales.length; i++) {          
            Locale.setDefault(availableLocales[i]);
            System.out.println("hashcode [" + test.hashCode() + "] - locale [" + Locale.getDefault() + "]");
        }

    }
}

Изходът е

hashcode [3556498] - locale [en_IE]
hashcode [3556498] - locale [ja_JP]
hashcode [3556498] - locale [es_PE]
hashcode [3556498] - locale [en]
hashcode [3556498] - locale [ja_JP_JP]
hashcode [3556498] - locale [es_PA]
hashcode [3556498] - locale [sr_BA]
hashcode [3556498] - locale [mk]
hashcode [3556498] - locale [es_GT]
hashcode [3556498] - locale [ar_AE]
hashcode [3556498] - locale [no_NO]
hashcode [3556498] - locale [sq_AL]
hashcode [3556498] - locale [bg]
hashcode [3556498] - locale [ar_IQ]
hashcode [3556498] - locale [ar_YE]
hashcode [3556498] - locale [hu]
hashcode [3556498] - locale [pt_PT]
hashcode [3556498] - locale [el_CY]
hashcode [3556498] - locale [ar_QA]
hashcode [3556498] - locale [mk_MK]
hashcode [3556498] - locale [sv]
hashcode [3556498] - locale [de_CH]
hashcode [3556498] - locale [en_US]
hashcode [3556498] - locale [fi_FI]
hashcode [3556498] - locale [is]
hashcode [3556498] - locale [cs]
hashcode [3556498] - locale [en_MT]
hashcode [3556498] - locale [sl_SI]
hashcode [3556498] - locale [sk_SK]
hashcode [3556498] - locale [it]
hashcode [3556498] - locale [tr_TR]
hashcode [3556498] - locale [zh]
hashcode [3556498] - locale [th]
hashcode [3556498] - locale [ar_SA]
hashcode [3556498] - locale [no]
hashcode [3556498] - locale [en_GB]
hashcode [3556498] - locale [sr_CS]
hashcode [3556498] - locale [lt]
hashcode [3556498] - locale [ro]
hashcode [3556498] - locale [en_NZ]
hashcode [3556498] - locale [no_NO_NY]
hashcode [3556498] - locale [lt_LT]
hashcode [3556498] - locale [es_NI]
hashcode [3556498] - locale [nl]
hashcode [3556498] - locale [ga_IE]
hashcode [3556498] - locale [fr_BE]
hashcode [3556498] - locale [es_ES]
hashcode [3556498] - locale [ar_LB]
hashcode [3556498] - locale [ko]
hashcode [3556498] - locale [fr_CA]
hashcode [3556498] - locale [et_EE]
hashcode [3556498] - locale [ar_KW]
hashcode [3556498] - locale [sr_RS]
hashcode [3556498] - locale [es_US]
hashcode [3556498] - locale [es_MX]
hashcode [3556498] - locale [ar_SD]
hashcode [3556498] - locale [in_ID]
hashcode [3556498] - locale [ru]
hashcode [3556498] - locale [lv]
hashcode [3556498] - locale [es_UY]
hashcode [3556498] - locale [lv_LV]
hashcode [3556498] - locale [iw]
hashcode [3556498] - locale [pt_BR]
hashcode [3556498] - locale [ar_SY]
hashcode [3556498] - locale [hr]
hashcode [3556498] - locale [et]
hashcode [3556498] - locale [es_DO]
hashcode [3556498] - locale [fr_CH]
hashcode [3556498] - locale [hi_IN]
hashcode [3556498] - locale [es_VE]
hashcode [3556498] - locale [ar_BH]
hashcode [3556498] - locale [en_PH]
hashcode [3556498] - locale [ar_TN]
hashcode [3556498] - locale [fi]
hashcode [3556498] - locale [de_AT]
hashcode [3556498] - locale [es]
hashcode [3556498] - locale [nl_NL]
hashcode [3556498] - locale [es_EC]
hashcode [3556498] - locale [zh_TW]
hashcode [3556498] - locale [ar_JO]
hashcode [3556498] - locale [be]
hashcode [3556498] - locale [is_IS]
hashcode [3556498] - locale [es_CO]
hashcode [3556498] - locale [es_CR]
hashcode [3556498] - locale [es_CL]
hashcode [3556498] - locale [ar_EG]
hashcode [3556498] - locale [en_ZA]
hashcode [3556498] - locale [th_TH]
hashcode [3556498] - locale [el_GR]
hashcode [3556498] - locale [it_IT]
hashcode [3556498] - locale [ca]
hashcode [3556498] - locale [hu_HU]
hashcode [3556498] - locale [fr]
hashcode [3556498] - locale [en_IE]
hashcode [3556498] - locale [uk_UA]
hashcode [3556498] - locale [pl_PL]
hashcode [3556498] - locale [fr_LU]
hashcode [3556498] - locale [nl_BE]
hashcode [3556498] - locale [en_IN]
hashcode [3556498] - locale [ca_ES]
hashcode [3556498] - locale [ar_MA]
hashcode [3556498] - locale [es_BO]
hashcode [3556498] - locale [en_AU]
hashcode [3556498] - locale [sr]
hashcode [3556498] - locale [zh_SG]
hashcode [3556498] - locale [pt]
hashcode [3556498] - locale [uk]
hashcode [3556498] - locale [es_SV]
hashcode [3556498] - locale [ru_RU]
hashcode [3556498] - locale [ko_KR]
hashcode [3556498] - locale [vi]
hashcode [3556498] - locale [ar_DZ]
hashcode [3556498] - locale [vi_VN]
hashcode [3556498] - locale [sr_ME]
hashcode [3556498] - locale [sq]
hashcode [3556498] - locale [ar_LY]
hashcode [3556498] - locale [ar]
hashcode [3556498] - locale [zh_CN]
hashcode [3556498] - locale [be_BY]
hashcode [3556498] - locale [zh_HK]
hashcode [3556498] - locale [ja]
hashcode [3556498] - locale [iw_IL]
hashcode [3556498] - locale [bg_BG]
hashcode [3556498] - locale [in]
hashcode [3556498] - locale [mt_MT]
hashcode [3556498] - locale [es_PY]
hashcode [3556498] - locale [sl]
hashcode [3556498] - locale [fr_FR]
hashcode [3556498] - locale [cs_CZ]
hashcode [3556498] - locale [it_CH]
hashcode [3556498] - locale [ro_RO]
hashcode [3556498] - locale [es_PR]
hashcode [3556498] - locale [en_CA]
hashcode [3556498] - locale [de_DE]
hashcode [3556498] - locale [ga]
hashcode [3556498] - locale [de_LU]
hashcode [3556498] - locale [de]
hashcode [3556498] - locale [es_AR]
hashcode [3556498] - locale [sk]
hashcode [3556498] - locale [ms_MY]
hashcode [3556498] - locale [hr_HR]
hashcode [3556498] - locale [en_SG]
hashcode [3556498] - locale [da]
hashcode [3556498] - locale [mt]
hashcode [3556498] - locale [pl]
hashcode [3556498] - locale [ar_OM]
hashcode [3556498] - locale [tr]
hashcode [3556498] - locale [th_TH_TH]
hashcode [3556498] - locale [el]
hashcode [3556498] - locale [ms]
hashcode [3556498] - locale [sv_SE]
hashcode [3556498] - locale [da_DK]
hashcode [3556498] - locale [es_HN]
person eon    schedule 28.08.2011
comment
Опитах вашия код със специални знаци (акценти и т.н.) и хеш кодът също не се променя според локала. - person Jérôme Verstrynge; 28.08.2011

Хешкодът на даден String обект не зависи от локала. Това трябва да е очевидно от javadoc, който сте свързали.

Въпреки това всяка трансформация, която произвежда различни знаци в низа, ще доведе до различен (не равен) низ и различен хешкод. Например, преобразуването на куп байтове в низ, използвайки различно кодиране на знаци по подразбиране може да доведе до различни знаци.


Обобщение, промяната на Locale не засяга пряко хешкодовете на String, но може да накара приложението ви да произвежда различни стойности на String и ТОВА ще се отрази на техните хешкодове.

person Stephen C    schedule 28.08.2011
comment
+1 за обяснението на това, можете ли да дадете пример за това, което казахте тук „превеждането на куп байтове в низ, използвайки различно кодиране на знаци по подразбиране, може да доведе до различни знаци“ - person eon; 29.08.2011
comment
@eon - основният проблем е, че ако изберете грешно кодиране, преводът или ще ви даде произволни странни знаци, или ще замени непреводими байтове с някакъв знак (напр. '?'), който показва неразпознат персонаж. Действителното поведение за неразпознат вход е неопределено, ако използвате (например) конструктор String за преобразуване на байтовете. - person Stephen C; 29.08.2011

Методът equals на String ясно заявява, че низовете са равни само ако представляват една и съща последователност от знаци (т.е. тук не се извършват преобразувания).

Въпреки че това не гарантира, че хешкодът не използва информация за локал (като цяло може), внедряването в Oracle JVM изглежда така:

public int hashCode() {
    int h = hash;
        int len = count;
    if (h == 0 && len > 0) {
        int off = offset;
        char val[] = value;

            for (int i = 0; i < len; i++) {
                h = 31*h + val[off++];
            }
            hash = h;
        }
        return h;
    }

Това използва само знаците и няма информация за локал.

person Mathias Schwarz    schedule 28.08.2011