• 字符串拘留池和字符串的不可变性


         我们在日常工作中,要判断2个变量是否相同,通常使用(==)或者是p1.Equals(p2),这个在很多情况下的判断是不准确的。而真正要判断2个对象是否相同,是看其在堆内存中的存储地址是否一样,所以要使用object.ReferenceEquals(p1,p2).看下面的代码:

    1  string s1 = "abc";
    2             string s2 = "abc";
    3             Console.WriteLine(object.ReferenceEquals(s1, s2));

    可以看到,返回结果是true,可以看到2个的确是一个对象,但是我们说2个不同的变量在堆中的地址应该不一样才对?为什么这个返回true呢?这是因为字符串有一个字符串拘留池的特性,在字符串拘留池中,维护着一个键值对,键就是字符串,而值就是堆地址,在声明s1后,再声明s2时,内存堆中看到2个变量的值相同。就把s1指向的常量在堆中的地址给了s2,所以返回true.再看下面的例子:

    string s1 = "abc";
                string s2 = "abc";
                
                string s3 = "a" + "b" + "c";
                Console.WriteLine(object.ReferenceEquals(s1,s3));

    这个返回值也是true,因为s3是3个常量相加,编译后其堆地址和s1,s2相同;而下面的情况不相同:

               string s1 = "abc";
                string s2 = "abc";
    
    
                string a = "a";
                string b = "b";
                string c = "c";
                //3个变量相加
                string s4 = a + b + c;
                Console.WriteLine(object.ReferenceEquals(s1, s4));

    可以看到返回值为false.这是因为a,b,c是3个变量,而上面那个例子中s3是3个常量相加。而字符串拘留池这个特性是针对字符串常量而言的。所以这里返回false.

    再看下面的例子:

    string s1 = "abc";
                string s2 = "abc";
    
                //只要new了,就创建了新对象
                string s5 = new string(new char[] { 'a', 'b', 'c' });
                Console.WriteLine(object.ReferenceEquals(s1, s5));

    这里仍旧返回false,因为在上面讲过,字符串拘留池这个特性是针对字符串常量而言的;而使用了new关键字后,肯定在内存堆中创建新对象。故这里返回false.

    总结:

    字符串拘留池(字符串池)是针对字符串常量而言的,对于字符串变量,没有这个特性。

    只要给变量赋值时使用了new关键字,就肯定在内存堆中创建新对象,那么堆中的地址就和要比较的(s1)不一样。

    延伸:

    string s1 = "abc";
                string s2 = "abc";
                Console.WriteLine("请输入一个字符串:");
                string s = Console.ReadLine();
                Console.WriteLine(object.ReferenceEquals(s1,s));

    程序运行时,我们输入abc,可以看到运行结果如下:

    这里用户在控制台中输入的值是变量,所以也会在内存堆中开辟空间(不是字符串常量),不具备字符串常量的拘留池特性,所以返回false.

    最后说一下字符串的不可变性,所谓字符串的不可变性就是指字符串一旦声明就不可改变。看下面代码:

    1 string s="abc";
    2 s=null;        //此时字符串abc虽然在堆内存中有,但是无法引用,而下面则不同:
    3 s="abcd";   //将栈中的变量s的堆地址改变了,重新指向一块堆内存地址。
  • 相关阅读:
    JavaPersistenceWithMyBatis3笔记-第2章Bootstrapping MyBatis-001XMl形式和Java形式
    JavaPersistenceWithMyBatis3笔记-第1章-001
    算法Sedgewick第四版-第1章基础-2.3 Quicksort-001快速排序
    算法Sedgewick第四版-第1章基础-2.1Elementary Sortss-008排序算法的复杂度(比较次数的上下限)
    算法Sedgewick第四版-第1章基础-2.1Elementary Sortss-007归并排序(自下而上)
    算法Sedgewick第四版-第1章基础-2.1Elementary Sortss-006归并排序(Mergesort)
    算法Sedgewick第四版-第1章基础-2.1Elementary Sortss-005插入排序的改进版
    算法Sedgewick第四版-第1章基础-2.1Elementary Sortss-004希尔排序法(Shell Sort)
    常用的Expression调用形式
    C#调用JAVA接口WSSE方式用WebClient方式
  • 原文地址:https://www.cnblogs.com/chens2865/p/3826526.html
Copyright © 2020-2023  润新知