首页 > 编程语言 >JDK源码——String相关

JDK源码——String相关

时间:2024-08-16 14:55:21浏览次数:9  
标签:字符 String JDK StringBuffer 源码 str 字符串 append

String

JDK源码中的String类是Java中最常用的类之一,它提供了许多用于处理字符串的方法。以下是一些常用的String类方法:

  1. 构造方法:

    • String():创建一个空字符串。
    • String(char[] value):根据字符数组创建一个新的字符串。
    • String(byte[] bytes, int offset, int length):根据字节数组的一部分创建一个新的字符串。
    • String(String original):根据另一个字符串创建一个新的字符串。
  2. 常用方法:

    • int length():返回字符串的长度。
    • boolean isEmpty():判断字符串是否为空。
    • char charAt(int index):返回指定索引处的字符。
    • int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引。
    • int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引。
    • String substring(int beginIndex):返回一个新字符串,它是此字符串的一个子字符串。
    • String substring(int beginIndex, int endIndex):返回一个新字符串,它是此字符串的一个子字符串。
    • boolean contains(CharSequence s):当且仅当此字符串包含指定的char值序列时,返回true。
    • boolean equals(Object anObject):将此 String 与指定的对象比较。
    • boolean equalsIgnoreCase(String anotherString):将此 String 与另一个 String 比较,不考虑大小写。
    • int compareTo(String anotherString):按字典顺序比较两个字符串。
    • String toLowerCase():将所有在此字符串中的字符都转换为小写。
    • String toUpperCase():将所有在此字符串中的字符都转换为大写。
    • String trim():返回字符串的副本,忽略前导空白和尾部空白。
    • static String valueOf(Object obj):返回一个表示指定的对象的字符串。
  3. 不可变特性:

    • String类是不可变的,这意味着一旦创建了String对象,就不能更改其内容。任何对String的操作都会生成一个新的String对象。

源码阅读

初始化

 private final char value[];

hashCode()和equals()

hashCode源码:

 public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

计算哈希值的方法如下:

  1. 初始化一个整数变量h为0。
  2. 如果h为0且字符串长度大于0,则遍历字符串中的每个字符。
  3. 对于每个字符,将其ASCII码值乘以31的幂(幂的次数等于当前字符的位置减去字符串长度),然后将结果累加到h上。
  4. 最后将计算出的哈希值赋给hash变量并返回。

这种哈希算法可以有效地减少哈希冲突的概率,提高字符串在哈希表中的查找效率。

equals源码:

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

具体实现如下:

  1. 首先检查当前对象(this)是否与传入的对象(anObject)地址相同,如果相同则返回true。
  2. 如果传入的对象是一个String类型的实例,将其转换为String类型并赋值给anotherString变量。
  3. 获取当前字符串的长度n,并与anotherString的长度进行比较。如果长度不相等,则直接返回false。
  4. 如果长度相等,将当前字符串的字符数组value和anotherString的字符数组value分别赋值给v1和v2。
  5. 使用一个循环遍历两个字符数组,逐个比较对应位置的字符是否相等。如果有不相等的字符,则返回false。
  6. 如果所有字符都相等,则返回true。
  7. 如果传入的对象不是String类型或者长度不相等,则返回false。

StringBuffer

StringBuffer是Java中的一个类,它用于处理可变的字符串。与String不同,StringBuffer对象的内容可以在运行时被修改,而不需要创建新的实例。这使得StringBuffer在处理大量字符串操作时比String更高效。

在这里插入图片描述

以下是一些常用的StringBuffer方法:

  1. append():将指定的数据添加到当前StringBuffer对象的末尾。
  2. insert():在指定位置插入指定的数据。
  3. delete():删除指定范围内的字符。
  4. reverse():反转当前StringBuffer对象中的字符顺序。
  5. capacity():返回当前StringBuffer对象的容量。
  6. length():返回当前StringBuffer对象的长度。
  7. setCharAt():将指定位置的字符替换为指定的字符。
  8. charAt():返回指定位置的字符。
  9. toString():将StringBuffer对象转换为String对象。

示例代码:

public class StringBufferExample {
    public static void main(String[] args) {
        // 创建一个空的StringBuffer对象
        StringBuffer sb = new StringBuffer();

        // 使用append()方法添加字符串
        sb.append("Hello");
        sb.append(" ");
        sb.append("World!");

        // 输出结果
        System.out.println(sb.toString()); // 输出:Hello World!

        // 使用insert()方法在指定位置插入字符串
        sb.insert(6, " Java");
        System.out.println(sb.toString()); // 输出:Hello JavaWorld!

        // 使用delete()方法删除指定范围的字符
        sb.delete(6, 10);
        System.out.println(sb.toString()); // 输出:HelloWorld!

        // 使用reverse()方法反转字符串
        sb.reverse();
        System.out.println(sb.toString()); // 输出:!dlroWolleH
    }
}

源码阅读

初始化方法

    /**
     * Constructs a string buffer initialized to the contents of the
     * specified string. The initial capacity of the string buffer is
     * {@code 16} plus the length of the string argument.
     *
     * @param   str   the initial contents of the buffer.
     */
    public StringBuffer(String str) {
        super(str.length() + 16);
        append(str);
    }

构造函数的参数是一个字符串str,它表示要初始化到字符串缓冲区的初始内容。

在构造函数内部,首先调用父类(CharSequence)的构造函数,传入一个长度值。这个长度值是字符串str的长度加上16。这样做是为了确保字符串缓冲区有足够的容量来容纳初始内容以及可能的后续修改。

然后,使用append(str)方法将字符串str的内容添加到字符串缓冲区中。这样,字符串缓冲区就包含了传入的字符串作为其初始内容。

append

  public synchronized StringBuffer append(Object obj) {
        toStringCache = null;
        super.append(String.valueOf(obj));
        return this;
    }
      public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }
     private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }

第一个方法是append(Object obj),它是一个同步方法,用于将一个对象添加到字符串缓冲区的末尾。首先,它将toStringCache设置为null,然后调用父类的append方法,将对象转换为字符串并添加到缓冲区。最后返回当前对象(即字符串缓冲区本身)。

第二个方法是append(String str),它是AbstractStringBuilder类的一个抽象方法,用于将一个字符串添加到字符串缓冲区的末尾。如果传入的字符串为null,它会调用appendNull()方法。否则,它会计算新字符串的长度,并确保缓冲区有足够的容量来容纳新的字符串。然后,使用getChars()方法将字符串的字符复制到缓冲区的字符数组中,并更新缓冲区的计数器。最后返回当前对象(即字符串缓冲区本身)。

第三个方法是ensureCapacityInternal(int minimumCapacity),它是一个私有方法,用于确保字符串缓冲区有足够的容量来容纳至少minimumCapacity个字符。如果需要的容量大于当前缓冲区的容量,它会创建一个新的字符数组,并将旧的字符数组的内容复制到新数组中。

StringBuilder

StringBuilder是一个可变的字符序列,主要用于高效地拼接字符串

StringBuilder类提供了与StringBuffer兼容的API,但不包括同步,这使得它在单线程中通常比StringBuffer性能更高。因此,在不需要考虑线程安全的情况下,建议使用StringBuilder代替StringBuffer。

在这里插入图片描述

源码阅读

初始化方法

 public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
    }

构造函数的参数是一个字符串str,它表示要初始化到字符串构建器的初始内容。

在构造函数内部,首先调用父类(CharSequence)的构造函数,传入一个长度值。这个长度值是字符串str的长度加上16。这样做是为了确保字符串构建器有足够的容量来容纳初始内容以及可能的后续修改。

然后,使用append(str)方法将字符串str的内容添加到字符串构建器中。这样,字符串构建器就包含了传入的字符串作为其初始内容。

append

   public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }


第一个方法是append(String str),它是StringBuilder类的一个公共方法,用于将一个字符串添加到字符串构建器的末尾。它首先调用父类的append方法,将字符串添加到字符数组中,然后返回当前对象(即字符串构建器本身)。

第二个方法是append(String str),它是AbstractStringBuilder类的一个抽象方法,用于将一个字符串添加到字符串构建器的末尾。如果传入的字符串为null,它会调用appendNull()方法。否则,它会计算新字符串的长度,并确保缓冲区有足够的容量来容纳新的字符串。然后,使用getChars()方法将字符串的字符复制到缓冲区的字符数组中,并更新缓冲区的计数器。最后返回当前对象(即字符串构建器本身)。

总结

StringStringBuilderStringBuffer
类别不可变字符串可变字符串可变字符串与同步
性能因为不可变,拼接字符串效率较低,每次拼接都会生成新的String对象。在单线程中,相比String效率更高,因为可以直接在原字符串上进行修改,不需要创建新对象。由于添加了同步,所以在多线程环境中是安全的,但在单线程中比StringBuilder慢。
线程安全线程安全,因为是不可变的不是线程安全的线程安全
修改方式不能被修改可以被修改可以被修改
常见用途适用于少量字符串操作和值的比较适用于大量字符串操作且不需要考虑线程安全的场景适用于大量字符串操作且需要考虑线程安全的场景
内部实现使用字符数组实现使用可变字符数组实现使用和StringBuilder相同的可变字符数组实现,但添加了同步
API提供自Java 1.0起存在自Java 1.5起引入自Java 1.2起引入

相同之处:

  1. 都是用来处理字符串的。
  2. 都可以包含相同的字符序列。

区别:

  1. 性能: String在拼接时会创建多个对象,而StringBuilderStringBuffer则在原有对象上进行修改,因此在性能上StringBuilderStringBuffer优于String
  2. 线程安全: String是不可变的,自然是线程安全的;StringBuffer是线程安全的,因为它的关键方法都被synchronized修饰;StringBuilder则不是线程安全的。
  3. API版本: String从Java 1.0开始就有,而StringBuilderStringBuffer分别从Java 1.5和1.2引入。
  4. 修改能力: String是不可修改的,而StringBuilderStringBuffer可以进行各种修改操作(如追加、插入、删除等)。
  5. 适用场景: 在需要多线程共享字符串时应该使用StringBuffer,在单线程或不需要线程安全的情况下,应优先选择性能更高的StringBuilder

标签:字符,String,JDK,StringBuffer,源码,str,字符串,append
From: https://blog.csdn.net/Luck_gun/article/details/141202702

相关文章

  • springboot个人健康管理-计算机毕业设计源码04385
    摘 要随着移动互联网的飞速发展,微信小程序因其便捷、高效、低成本的特点,成为了连接用户与服务之间的桥梁。特别是在健康管理领域,微信小程序为用户提供了一个随时随地进行健康数据记录、查询和管理的平台。而SpringBoot作为一种轻量级的Java开发框架,因其快速搭建、易于集成......
  • django空巢老人志愿服务系统-计算机毕业设计源码58726
    摘 要随着社会老龄化问题日益突出,空巢老人群体的关注和关怀日益重要。本研究设计并实现了基于Python的空巢老人志愿服务系统,旨在利用技术手段提供更多关爱和支持给空巢老人群体。该系统结合Python编程语言的灵活性和易用性,实现了慈善捐赠、医院信息查询、志愿活动发布、志......
  • 一个创新的国密前后分离快速开发平台,提供工作流、多租户、多数据源、Vue3表单设计器,高
    前言在当前的软件开发领域,尤其是企业级应用开发中,开发者面临着诸多挑战,如代码安-全、数据加密、国产化适配等。传统的开发平台往往难以满足这些日益增长的需求,特别是在国产化替代的大背景下,对于符合国家安-全标准的软件需求愈发迫切。这就需要一款能够解决上述痛点,同时提供高......
  • 一款开箱即用的整合第三方登录的开源组件,整合了国内外数十家知名平台的OAuth登录(附源
    前言在现代应用开发中,第三方登录认证是一个不可或缺的功能,它为用户带来了便捷的登录体验。然而,开发者在实现这一功能时往往会遇到一些痛点:需要对接多个第三方平台的SDK,每增加一个平台就要编写一套新的代码,导致代码维护变得复杂且困难。此外,从头开发一个完整的登录功能不仅需要......
  • SSM-国外鞋服代购平台-97782(免费领源码+开发文档)可做计算机毕业设计JAVA、PHP、爬虫、
    SSM国外鞋服代购平台摘 要随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,鞋服代购平台当然也不例外。代购平台是以实际运用为开发背景,运用软件工程原理和开发方法,采用Java技术构建的一个管理系统。整个开发过......
  • springboot电竞专题网站的设计与实现-附源码641314
    摘 要近年来,随着移动互联网的快速发展,电子商务越来越受到网民们的欢迎,电子商务对国家经济的发展也起着越来越重要的作用。简单的流程、便捷可靠的支付方式、快捷畅通的物流快递、安全的信息保护都使得电子商务越来越赢得网民们的青睐。现今,大量的计算机技术应用于商业领域,......
  • 基于springboot教学评价系统的设计与实现-附源码641310
    摘  要信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题。针对教学评价等问题,对如何通过计算机教学评价进行研究分析,然后开发设计出教学评价系统已解决问......
  • C++ string类型常用操作
    string类型操作字符串切割str.substr(索引,切割的个数) -> 返回字符串注意:第二个参数为切割的个数stringbuf="abcdefg";buf.substr(0,2);//结果为"ab"buf.substr(1,3);//结果为"bcd"字符串输入使用getline读入字符串可以保留字符串中的空格 getline(cin......
  • Springcloud大学生在线学习平台-计算机毕业设计源码43038
    目录1绪论1.1选题背景与意义1.2国内外研究现状1.3论文结构与章节安排2系统分析2.1可行性分析2.1.1经济可行性2.1.2技术可行性2.1.3社会可行性2.2系统流程分析2.2.1系统开发流程2.2.2用户登录流程2.2.3系统操作流程2.2.4添加信息流程2.2.5......
  • 基于Java中的SSM框架实现智慧医疗预约挂号管理系统项目【项目源码+论文说明】计算机毕
    基于Java中的SSM框架实现智慧医疗预约挂号管理系统演示摘要伴随着人们对医疗的关注度越来越高,对于信息化就医的发展也是当今社会发展的最为重要的问题之一。为了进一步的促进医疗事业的信息化发展工作,许多的大型的医院或者是医疗机构也在逐步的开展了信息化的就医和信息化......