• 刨析 代码中常用的 基础 String 对象类(源码解析)


    一、引言

    String对象作为 所有代码语言(JavaScript、C#、JAVA、C++、VB、Pyhon ... )中最基础的一个常用的代码对象,你有去好好了解过它吗?如果没有的话那今天我就带大家好好来了解一下。 (~ ̄▽ ̄)~ 废话不多说,我们一起来看看吧,走起!【我这里以JAVA为例】

    三、String 对象的实现

    String对象是 Java 中使用最频繁的对象之一,所以 Java 公司也在不断的对String对象的实现进行优化,以便提升String对象的性能,看下面这张图,一起了解一下String对象的优化过程。

    在这里插入图片描述
    1. 在 Java6 以及之前的版本中

    String对象是对 char 数组进行了封装实现的对象,主要有四个成员变量:char 数组、偏移量 offset、字符数量 count、哈希值 hash。

    String对象是通过 offset 和 count 两个属性来定位 char[] 数组,获取字符串。这么做可以高效、快速地共享数组对象,同时节省内存空间,但这种方式很有可能会导致内存泄漏。

    2. 从 Java7 版本开始到 Java8 版本

    从 Java7 版本开始,Java 对String类做了一些改变。String类中不再有 offset 和 count 两个变量了。这样的好处是String对象占用的内存稍微少了些,同时 String.substring 方法也不再共享 char[],从而解决了使用该方法可能导致的内存泄漏问题。

    3. 从 Java9 版本开始

    将 char[] 数组改为了 byte[] 数组,为什么需要这样做呢?我们知道 char 是两个字节,如果用来存一个字节的字符有点浪费,为了节约空间,Java 公司就改成了一个字节的byte来存储字符串。这样在存储一个字节的字符是就避免了浪费。

    在 Java9 维护了一个新的属性 coder,它是编码格式的标识,在计算字符串长度或者调用 indexOf() 函数时,需要根据这个字段,判断如何计算字符串长度。coder 属性默认有 0 和 1 两个值, 0 代表Latin-1(单字节编码),1 代表 UTF-16 编码。如果 String判断字符串只包含了 Latin-1,则 coder 属性值为 0 ,反之则为 1。

    三、String 源码 解析

    1、String对象用于保存字符串,也就是一组字符序列。

    在这里插入图片描述
    2、字符串常量对象是用双引号括起来的字符序列。

    在这里插入图片描述

    3、字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节。

    在这里插入图片描述

    4、String类较常用构造器:

     String s1 = new String();
     String s2 = new String(String original);
     String s3 = new String(char[] a);
     String s4 = new String(char[] a, int startIndex, int count);
    
    • 1
    • 2
    • 3
    • 4

    5、String类继承:
    5.1、实现了接口 Serializable【String可以串行化:可以在网络传输】
    5.2、实现了接口 Comparable【String对象可以比较大小】

    在这里插入图片描述

    6、String是final类,不能被其他的类继承。

    7、String有属性,private final char value[]; 用于存放字符串内容。

    8、一定要注意:value是一个final类型,不可以修改。即value不能指向新的地址,但是单个字符内容是可以变化。

    在这里插入图片描述

    四、String 使用

    两种方式

    方式一:直接使用双引号得到字符串对象

    
    	//方式一:直接使用双引号得到字符串对象
    	   String name = "我爱你中国!";
    
    
    • 1
    • 2
    • 3
    • 4

    方式二:使用String构造类

    1.public String():创建一个空白字符串对象,不含有任何内容 (几乎不用)

    
    	// 1.public String():创建一个空白字符串对象,不含有任何内容 (几乎不用)
           String s = new String();
        
    
    • 1
    • 2
    • 3
    • 4

    2.public String(String):根据传入的字符串内容,来创建字符串对象(几乎不用)

    
    	// 2.public String(String):根据传入的字符串内容,来创建字符串对象(几乎不用)
            String s2 = new String("我是中国人"); //灰色表示可有可无
        
    
    • 1
    • 2
    • 3
    • 4

    3.public String(char[] c):根据字符数组的内容,来创建字符串对象

    
    	// 3.public String(char[] c):根据字符数组的内容,来创建字符串对象
            char[] chars = {'a' , 'b' , '中' , '国'};
            String s3 = new String(chars);
            System.out.println(s3);
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.public String(byte[] b):根据字节数组的内容,来创建字符串对象

    
    	// 4.public String(byte[] b):根据字节数组的内容,来创建字符串对象
            byte[] bytes = {97, 98, 99, 65, 66, 67};
            String s4 = new String(bytes);
            System.out.println(s4);
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    区别小结
    区别一:以 “” 方式给出的字符串对象,在字符串常量池中存储,而且相同内容只会在其中存储一份。
    区别二:通过构造器new对象,每new一次都会产生一个新对象,放在堆内存中。

    五、String 对象方法

    方法描述
    charAt返回在指定位置的字符。
    charCodeAt返回在指定的位置的字符的 Unicode 编码。
    concat连接两个或更多字符串,并返回新的字符串。
    endsWith判断当前字符串是否是以指定的子字符串结尾的(区分大小写)。
    fromCharCode将 Unicode 编码转为字符。
    indexOf返回某个指定的字符串值在字符串中首次出现的位置。
    includes查找字符串中是否包含指定的子字符串。
    lastIndexOf从后向前搜索字符串,并从起始位置(0)开始计算返回字符串最后出现的位置。
    match查找找到一个或多个正则表达式的匹配。
    repeat复制字符串指定次数,并将它们连接在一起返回。
    replace在字符串中查找匹配的子串,并替换与正则表达式匹配的子串。
    replaceAll在字符串中查找匹配的子串,并替换与正则表达式匹配的所有子串。
    search查找与正则表达式相匹配的值。
    slice提取字符串的片断,并在新的字符串中返回被提取的部分。
    split把字符串分割为字符串数组。
    startsWith查看字符串是否以指定的子字符串开头。
    substr从起始索引号提取字符串中指定数目的字符。
    substring提取字符串中两个指定的索引号之间的字符。
    toLowerCase把字符串转换为小写。
    toUpperCase把字符串转换为大写。
    trim去除字符串两边的空白。
    toLocaleLowerCase根据本地主机的语言环境把字符串转换为小写。
    toLocaleUpperCase根据本地主机的语言环境把字符串转换为大写。
    valueOf返回某个字符串对象的原始值。
    toString返回一个字符串。

    六、StringBuffer 与 StringBuilder

    String 类是保存字符串常量的。每次更新都需要重新开辟空间,效率较低,因此 java 设计者提供了StringBuilder和StringBuffer 来增强 String 的功能,并提高效率。
    StringBuilder和StringBuffer 都 继 承 于 AbstractStringBuilder

    1、 StringBuffer类

    java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删。
    许多方法与String相同,但是StringBuffer是可变长度的,StringBuffer是一个容器。

    
    1StringBuffer是一个final类,不能被继承。
    2、实现了Serializable接口,可以保存到文件,或网络传输;
    3、继承了抽象类AbstractStringBuilder4AbstractStringBuilder中有属性char[] value,不是final,该value数组存放字符串内容,因此存放在堆中;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    2、 StringBuilder类

    1、一个可变的字符序列。此类提供一个与StringBuffer兼容的API,但不保证同步(StringBuilder不是线程安全)。该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候 。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer要快。

    2、在StringBuilder上的主要操作是append和insert方法,可重载这些方法,以接受任意类型的数据。

    3、String VS StringBuffer

    1、String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率较低。private final char value[];

    2、StringBuffer保存的是字符串常量,里面的值可以更改,每次StringBuffer的更新实际上可以更新内容,不能更新地址,效率较高。char[] value;这个放在堆中。

    4、总结

    三种类型的区别

    StringBuilder和StringBuffer非常类似,均代表可变的字符序列,而且方法也不一样。
    1、String:不可变字符序列,效率低,但是复用率高。
    2、StringBuffer:可变字符序列、效率较高(增删)、线程安全。
    3、StringBuilder:可变字符序列、效率最高、线程不安全。

    String、StringBuffer和StringBuilder的 使用原则:

    1、如果字符串存在大量的修改操作,一般使用StringBuilder或StringBuffer。
    2、如果字符串存在大量的修改操作,并在单线程的情况,使用StringBuilder。
    3、如果字符串存在大量的修改操作,并在多线程的情况,使用StringBuffer。
    4、如果我们字符串很少修改,被多个对象引用,使用String,比如配置信息等。

    五、关联文章

    [刨析 equals 比较 漏洞与误区]

  • 相关阅读:
    JavaScript 中的变量声明与赋值
    Spring Cloud--从零开始搭建微服务基础环境【二】
    Mock平台3-初识Antd React 开箱即用中台前端框架
    【ASP.NET Core】在 Mini-API 中注入服务
    [Unity]OCR识别--Tesseract篇
    路网双线合并单线——ArcGISpro 解决方法
    oracle-AWR报告生成方法
    mysql的date_format()函数格式月份的坑
    飞行动力学 - 第25节-特征根与动稳定性 之 基础点摘要
    【Java集合框架】18——Map接口
  • 原文地址:https://blog.csdn.net/GoodburghCottage/article/details/126639829