Является ли хэш-код строки Java независимым от локали?

Является ли Java String.hashcode() полностью не зависит от локали? Другими словами, если кто-то возится со значением по умолчанию 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)


Локаль не влияет на хэш-код строки (напрямую). Он основан исключительно на символах, хранящихся в String. Хэш-код генерируется

char[] val;

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

но проблема в том, как создается строка. Если это, например, результат toUpperCase, который зависит от локали, очевидно, что результирующая строка зависит от локали, как и хэш-код.

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, который вы связали.

Однако любое преобразование, производящее другие символы в строке, приведет к другой (не равной) строке и другому хэш-коду. Например, преобразование набора байтов в строку с использованием другой кодировки символов по умолчанию может привести к получению разных символов.


Резюме: изменение локали не влияет напрямую на хэш-коды 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