【问题标题】:Is Java string hashcode independent of locale?Java字符串哈希码是否独立于语言环境?
【发布时间】:2011-08-27 23:59:51
【问题描述】:

Java String.hashcode() 是否完全独立于Locale?换句话说,如果有人使用默认的Locale,我们是否 100% 确定这不会影响哈希码?

我们知道这种摆弄会影响toUpperCase()toLowerCase()

【问题讨论】:

标签: java locale hashcode


【解决方案1】:

Locale 不会(直接)影响字符串的 hashCode。它完全基于存储在字符串中的字符。 hashCode 由

生成
char[] val;

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

但问题是如何生成字符串。例如,如果是依赖于Locale的toUpperCase的结果,那么很明显得到的String是依赖于Locale的,hashCode也是如此。

【讨论】:

    【解决方案2】:

    好问题,我进行了快速测试,似乎更改默认语言环境不会(谢天谢地)更改哈希码...

    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]
    

    【讨论】:

    • 我用特殊字符(重音等)尝试了您的代码,并且哈希码也不会根据语言环境而改变。
    【解决方案3】:

    String 上的 equals 方法明确指出,字符串只有在表示相同的字符序列时才相等(也就是说,这里不进行任何转换)。

    虽然这并不能保证哈希码不使用语言环境信息(通常可能),但 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;
        }
    

    这仅使用字符,没有区域信息。

    【讨论】:

      【解决方案4】:

      给定String 对象的哈希码不依赖于语言环境。从您链接的 javadoc 中应该可以看出这一点。

      但是,任何在字符串中产生不同字符的转换都会导致不同(不相等)的字符串和不同的哈希码。例如,使用不同的默认字符编码将一堆字节转换为字符串可以产生不同的字符。


      总结,更改区域设置不会直接影响字符串哈希码,但它可能会导致您的应用程序生成不同的字符串值,这会影响它们的哈希码。

      【讨论】:

      • +1 用于解释这一点,您能否举个例子说明您在此处所说的“使用不同的默认字符编码将一堆字节转换为字符串会导致不同的字符”
      • @eon - 主要问题是如果你选择了 wrong 编码,翻译要么给你“随机奇怪的字符”,要么用一些不可翻译的字节替换表示无法识别的字符的字符(例如“?”)。如果您使用(例如)String 构造函数来转换字节,则无法识别的输入的实际行为是“未指定的”。
      猜你喜欢
      • 2013-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-28
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      相关资源
      最近更新 更多