zoukankan      html  css  js  c++  java
  • String

    一、概述

    String是我们平常用得最多的基元类型之一,虽然我们经常使用而且感到非常熟悉;但很多朋友只知道一个字符串的定义、使用或知道如何使用StringBuilder来达到高效构建字符串,但是有多少朋友有兴趣去了解背后的一些不为我们知道的秘密

    二、为什么把String加入到基元类型中

    在以前的面向过程语言中,并没有String这个类型,定义一个字符串的方式则采用一个Char[],虽然提供了对字符串的操作、比较等函数,但是还是不够方便也不太符合面向对象做法,所以在面向对象语言中,string也加入了基元类型的队列中;

    三、String核心特征immutable(不可变)

    代表一个不可变的顺序字符集,也就是说一经创建,字符串编不能以任何方式进行修改;具有以下3个优点:

    1.     允许在一个字符串上执行各种操作,而不实际地更改字符串;

    2.     在操作或访问一个字符串的时候不会发生线程同步的问题;

    3.     基于性能的考虑,String类型与CLR紧密集成,CLR知道String类型中定义的字段如何布局,而且CLR会直接访问,所以开发的时只好将String定义为密封类(Sealed);

    四、被重写的两个方法GetHashCodeEquals

    1.     GetHashCode方法进行了重写,目的是为了满足两个字符串的判断;

    2.     Equals方法进行重写,其中Equals方法最终还是调用了GetHashCode方法来进行判断;

    五、“==”、EqualsCompare,字符串判断到底用哪个好点?

    1.     String对“==”操作符进行重载,内部实现进行了空值判断后,再调用Equals进行判断(所以采用"=="操作符,不会抛出空指针异常)

    2.     StringEquals方法,因为调用Equals方法的时候,直接通过返回HashCode进行比较,效率最高,有可能对象为空,有可能会抛空指针异常,所以用的时候需要留意;

    3.     StringCompare方法:该方法是一个静态方法,内部实现是首先判断字符串的长度是否相等,如果长度不相等,直接返回结果,如果长度相等,则会采用逐个字符进行判断,如果方法中的CultureInfo不为空,则判断的过程中会逐个字符进行展开(这里涉及到语言的问题,如果采用德语会把"β"展开为"ss",所以”strasse”staβe的判断结果是相同的); 

    注:如果一般情况下,建议采用Equals进行判断,效率最高,但如果无法确保方法Equals的调用者是否不为null,建议还是采用==或者 "XXXX".Equals(obj),如果需要用到多语言(国际化)判断的时候,可以考虑用Compare

    六、拘留池(Interning

    字符串操作(比如Compare)的做法是很多程序常见的操作,这样的操作可能造成内存中复制同一个字符串的多个实例(算法内部操作导致),为了达到节省内存的效果,CLR采用了一种叫“字符串留用的技术”(String Interning),开辟了一块名为“拘留池”的空间专门用于存放字符串,而拘留池在程序初始化的时候,会把元数据默认加载到“拘留池”中,而且不会受到垃圾回收器的影响,只有在程序被关闭的时候才会释放“拘留池”中的资源;

    七、存储方式,大致分为以下3种:

    1.     以常量的方式来定义很保存字符串,比如:var value = "abc";

    2.     以对象的方式来保存到堆中:比如 var value = new string('a');

    3.     以对象的方式构造然后存放到拘留池(其实常量的方式定义后,默认也会把字符串加入到驻留池中); 

    可以参考以下代码和内存分配图进行理解:

        //验证字符串常量默认加载到元数据,默认会把元数据中的字符串加载到拘留池
    var data = "abc";       //此声明方式,会把该变量定义为字符串常量,然后存入元数据中
        var a = "a";            //同上
        var b = "b";            //同上
        var c = "c";            //同上
        var ab = a + b;         //根据线程栈上的a、b地址获取到堆上的a、b实例,然后把两个实例的结果进行运算后产生一个新对象,最后新对象地址赋给ab变量
        var abc = a + b + c;    //同上
        var abResult = string.IsInterned(ab);        //返回结果为null,也就是说没有把字符串"ab"存入拘留池中;
        var abcResult = string.IsInterned(abc);     //返回结果为"abc",也就是说已经把字符串(这里是常量)"abc"存放到拘留池中;
        var empty = string.Empty;        //初始化的时候,从String类型对象中获取静态属性Empty的数据;
        var strEmpty = "";               //产生一个值为空的String对象;

        var a1 = "abc";
        var a2 = string.IsInterned(a1);
        var result = object.ReferenceEquals(a1, a2);    

                

         注:默认是不从拘留池中加载,而是直接采用ldstr的特殊指令获得字符串”abc”,但可以确认的是”元数据”跟“拘留池”中的字符串是用个对象; 

    八、案例分析

      1. 以下代码的HashCode是否相同,它们是否是同个对象;

          var A = "ab" + "c";
          var B = "abc";
     
      2. 以下代码的HashCode是否相同,他们是否是同个对象:  
          var A = Console.ReadLine();   //输入"abc"
          var B = Console.ReadLine();   //输入"abc"
     
      3. 以下代码的HashCode是否相同,他们是否是同个对象:
          var A = Console.ReadLine(); //输入"abc"
          var B = Console.ReadLine(); //输入"abc"
          var A = string.Intern(B);

     结果请查看这里

  • 相关阅读:
    App开放接口api安全性—Token签名sign的设计与实现
    查看文件(或文件夹)被哪个进程使用【文件已在另一程序中打开】
    利用递归将数组转码
    h5 定位
    使用OAuth Server PHP实现OAuth2服务
    在Linux上安装jdk,mysql,tomcat的准备工作
    Core Java笔记
    随机森林简介
    Linux 查看操作系统版本
    RNA_seq GATK 最佳实践
  • 原文地址:https://www.cnblogs.com/smlAnt/p/3501119.html
Copyright © 2011-2022 走看看