1

我和我的朋友正在讨论 Dotnet 框架中的字符串,它们如何是引用类型但行为却像值类型(不可变)。我们都知道字符串是 CLR 内部的,但是在简短的讨论中我们并没有真正得出结论,字符串是如何由 CLR/Framework 创建和管理的。

例如,在下面的代码中,显然s1s2是不同的实例,但是正如您所看到的,当我s2.ToUpper()执行结果时,请参考s1.

    public static void Main (string[] args)
    {
        string s1 = "HELLO";
        string s2 = "hello";

        Console.WriteLine (s1.GetHashCode()); //Prints 68624562
        Console.WriteLine (s2.GetHashCode()); //Prints 99162322
        Console.WriteLine (s2.ToUpper().GetHashCode()); //Prints 68624562 too!
    }

所以,问题是调用s2.ToUpper()CLR 是否创建了新字符串"HELLO"并检查它是否已经存在,如果是,那么丢弃新创建的字符串?有人可以解释这里的魔法吗?

4

5 回答 5

3

String.GetHashCode() 生成基于字符串内容的哈希值。因此,相同的字符串生成相同的哈希是完全自然的。这意味着您不能断定 ToUpper() 返回的字符串引用必须与 s1 引用匹配。事实并非如此,实施起来太昂贵了。

您可以通过测试此代码来验证:

    static void Main(string[] args) {
        var s1 = "hello";
        var s2 = "HELLO";
        var s3 = s1.ToUpper();
        bool eq = object.ReferenceEquals(s2, s3);
        System.Diagnostics.Debug.Assert(!eq);
    } 
于 2012-04-08T17:46:00.137 回答
3

GetHashCode()对于相同的输入,两个调用给出相同的结果并不奇怪,这就是散列的意义......

相反,当你这样做时:

Console.WriteLine(Object.ReferenceEquals(s2.ToUpper(), s1));

它只是返回false。因此,您确实有两个string实例,它们都具有相同的内容。

我认为您需要复习有关散列、散列码和相等性的知识。

还是您来自Java?也许您得到的印象是哈希码与对象引用值有关,因为Object.getHashCode()的文档指出:

在合理可行的情况下,由 Object 类定义的 hashCode 方法确实为不同的对象返回不同的整数。(这通常通过将对象的内部地址转换为整数来实现,但 JavaTM 编程语言不需要这种实现技术。)

于 2012-04-08T17:47:16.070 回答
2

您不能用于GetHashCode()唯一标识实例。对于具有相同值的两个不同对象,哈希码必须相同。否则它不能作为哈希码工作。

于 2012-04-08T17:45:39.277 回答
1

s2.ToUpper() 只是方法调用,不会改变 s2 对象的值(s2 是 String 类型的对象)。它采用 s2 的值并返回具有“HELLO”值的 String 类的新实例(ToUpper() 方法的结果)。在 Main 函数的范围内仍然有两个对象 s1 和 s2,它们的值保持不变。

于 2012-04-08T17:57:34.967 回答
0

要添加,请回答您的另一部分...

如果你也检查这个Object.ReferenceEquals(s2.ToUpper(), s2),你会发现它也是错误的。

字符串是immutable- 在这种情况下意味着ToUpper()返回一个新实例。

所以答案是肯定的,“HELLO”是新字符串。

但是,正如其他人所说,GetHashCode()它只是一个“散列值”——它主要用于在处理散列和字典时有一个多样化的算法来“填充桶”。

或查看此链接What is the best algorithm for a override System.Object.GetHashCode? - 答案 - 让您很好地了解散列算法的工作原理 - 以及为什么它不是唯一的 - 以及为什么对于具有相同内容的字符串来说它可能是相同的。

或者这个http://ericlippert.com/2011/02/28/guidelines-and-rules-for-getashcode/

于 2012-04-08T18:03:48.360 回答