【面试精讲】String是如何实现的?String源码分析

【面试精讲】String是如何实现的?String源码分析

目录

一、String实现机制

二、String不可变性(使用final修饰)

三、String 和 StringBuilder、StringBuffer 的区别

四、==和equals的区别

五、String创建对象与JVM辨析

六、String源码解析

1、compareTo()

2、 equals() 

总结

 博主v:XiaoMing_Java


在Java中,String类是使用最频繁的类之一。由于其不可变性、效率以及如何影响内存使用等方面的特点,String类成为了Java编程语言的一个核心组成部分。本文深入探讨String的实现机制、它的源码结构、特点以及用final修饰的好处。

一、String实现机制

在Java中,String被设计为不可变(immutable)的对象。这意味着一旦String对象被创建,它所包含的字符序列就不能被修改。每次对字符串进行操作时(例如拼接、替换字符等),实际上都会创建一个新的String对象。

从JDK 1.0到JDK 8,String内部是通过一个char数组来实现的,保存着所有的字符数据。从JDK 9开始,String类的内部实现改为使用byte数组加上一个编码标记(coder),以更有效地处理不同的字符集,优化内存使用和性能。

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    // 用于存储字符串的值
    private final char value[];

    // 缓存字符串的 hash code
    private int hash; // Default to 0
}

自JDK 9起,为了提升空间效率和性能,String的内部表示发生了变化,使用byte数组加上一个编码标志字段coder来存储字符串,如下所示:

// JDK 9及以后的String内部结构
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    // 实际存储字符串内容的byte数组
    private final byte[] value;

    // 字符串使用的编码标识(用于区分使用Latin-1还是UTF-16编码)
    private final byte coder;

    // 缓存字符串的哈希码
    private int hash; // 默认为0

    // 构造方法之一,用于从字符数组初始化字符串
    public String(char[] value) {
        // 这里简化了实际的实现细节
        this.value = StringLatin1.toBytes(value);
        this.coder = LATIN1;
    }

    // length() 方法实现
    public int length() {
        return value.length >> coder;
    }
}

二、String不可变性(使用final修饰)

String对象一旦被创建,其内容就不能被改变。任何对String的修改操作都会导致新的String对象的生成。这个特性带来了以下好处:

安全性:String常作为参数传递,其不可变性保证了数据不会被意外改变。防止子类改变父类(String)的行为,确保所有String实例都具有String定义的行为。

线程安全:在多线程环境下,String可以被自由共享而无需同步控制。

高效:因为String的内容不变,所以其哈希码可以被缓存,提高哈希表操作的效率。性能优化:

简化设计:由于不需要考虑子类的影响,使得String类的设计更简单、更稳定

 

三、String 和 StringBuilder、StringBuffer 的区别

String类重载了+运算符,使得字符串连接操作非常方便。然而,频繁的字符串连接操作会产生大量临时字符串对象,影响性能。为了解决这个问题,Java引入了StringBuilderStringBuffer两个类,它们允许在单个字符序列上执行可变操作。

因为 String 类型是不可变的,所以在字符串拼接的时候如果使用 String 的话性能会很低,因此我们就需要使用另一个数据类型 StringBuffer,它提供了 append 和 insert 方法可用于字符串的拼接,它使用 synchronized 来保证线程安全。

在 JDK 1.5 有了 StringBuilder,它同样提供了 append 和 insert 的拼接方法,在非并发操作的环境下可使用 StringBuilder 来进行字符串拼接。

四、==和equals的区别

== 对于基本数据类型来说,是用于比较 “值”是否相等的;而对于引用类型来说,是用于比较引用地址是否相同的。

// Object 中的 equals() 方法其实就是 ==
public boolean equals(Object obj) {
    return (this == obj);
}

// 而String重写equals()方法把它修改成比较两个字符串的值是否相等
public boolean equals(Object anObject) {
    // 对象引用相同直接返回 true
    if (this == anObject) {
        return true;
    }

    // 判断需要对比的值是否为 String 类型,如果不是则直接返回 false
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {

            // 把两个字符串都转换为 char 数组对比
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;

            // 循环比对两个字符串的每一个字符
            while (n-- != 0) {

                // 如果其中有一个字符不相等就 true false,否则继续对比
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

五、String创建对象与JVM辨析

String 常见的创建方式有两种,new String() 的方式和直接赋值的方式

直接赋值的方式会先去字符串常量池中查找是否已经有此值,如果有则把引用地址直接指向此值,否则会先在常量池中创建,然后再把引用指向此值;

new String() 的方式一定会先在堆上创建一个字符串对象,然后再去常量池中查询此字符串的值是否已经存在,如果不存在会先在常量池中创建此字符串,然后把引用的值指向此字符串

JDK 1.7 之后把永生代换成的元空间,把字符串常量池从方法区移到了 Java 堆上。

六、String源码解析

1、compareTo()

public int compareTo(String anotherString) {
    int len1 = value.length;
    int len2 = anotherString.value.length;

    // 获取到两个字符串长度最短的那个 int 值
    int lim = Math.min(len1, len2);
    char v1[] = value;
    char v2[] = anotherString.value;
    int k = 0;

    // 对比每一个字符
    while (k < lim) {
        char c1 = v1[k];
        char c2 = v2[k];
        if (c1 != c2) {
            // 有字符不相等就返回差值
            return c1 - c2;
        }
        k++;
    }
    return len1 - len2;
}

2、 equals() 

public boolean equals(Object anObject) {
    // 对象引用相同直接返回 true
    if (this == anObject) {
        return true;
    }

    // 判断需要对比的值是否为 String 类型,如果不是则直接返回 false
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {

            // 把两个字符串都转换为 char 数组对比
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;

            // 循环比对两个字符串的每一个字符
            while (n-- != 0) {
                // 如果其中有一个字符不相等就 true false,否则继续对比
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

总结

String在Java中的地位极其重要,其设计精巧、使用广泛。通过不可变性设计,String提供了高度的安全性和线程安全,同时final修饰符进一步确保了其不变契约的稳定性。了解String的内部实现和特点对于写出高效、安全和易维护的Java代码至关重要。

Java开发者应当熟练掌握String的使用,并在合适的场景选择使用StringBuilderStringBuffer以优化性能。此外,深入理解String的设计哲学也有助于开发者设计自己的不可变类,为构建稳定和高效的Java应用打下坚实的基础。

如果本文对你有帮助 欢迎 关注 、点赞 、收藏 、评论, 博主才有动力持续记录遇到的问题!!!

 博主v:XiaoMing_Java

  📫作者简介:嗨,大家好,我是 小明(小明Java问道之路),互联网大厂后端研发专家,2022博客之星TOP3 / 博客专家 / CSDN后端内容合伙人、InfoQ(极客时间)签约作者、阿里云签约博主、全网 6 万粉丝博主。


🍅 文末获取联系 🍅  👇🏻 精彩专栏推荐订阅收藏 👇🏻

专栏系列(点击解锁)

学习路线(点击解锁)

知识定位

🔥Redis从入门到精通与实战🔥

Redis从入门到精通与实战

围绕原理源码讲解Redis面试知识点与实战

🔥MySQL从入门到精通🔥

MySQL从入门到精通

全面讲解MySQL知识与企业级MySQL实战

🔥计算机底层原理🔥

深入理解计算机系统CSAPP

以深入理解计算机系统为基石,构件计算机体系和计算机思维

Linux内核源码解析

围绕Linux内核讲解计算机底层原理与并发

🔥数据结构与企业题库精讲🔥

数据结构与企业题库精讲

结合工作经验深入浅出,适合各层次,笔试面试算法题精讲

🔥互联网架构分析与实战🔥

企业系统架构分析实践与落地

行业最前沿视角,专注于技术架构升级路线、架构实践

互联网企业防资损实践

互联网金融公司的防资损方法论、代码与实践

🔥Java全栈白宝书🔥

精通Java8与函数式编程

本专栏以实战为基础,逐步深入Java8以及未来的编程模式

深入理解JVM

详细介绍内存区域、字节码、方法底层,类加载和GC等知识

深入理解高并发编程

深入Liunx内核、汇编、C++全方位理解并发编程

Spring源码分析

Spring核心七IOC/AOP等源码分析

MyBatis源码分析

MyBatis核心源码分析

Java核心技术

只讲Java核心技术

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/458855.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Mybatis 动态sql环境搭建(学习笔记16)

什么是动态sql:根据不同的条件生成不同的sql语句 借助功能强大的基于 OGNL 的表达式&#xff0c;MyBatis 3 替换了之前的大部分元素&#xff0c;大大精简了元素种类&#xff0c;现在要学习的元素种类比原来的一半还要少。 ifchoose (when, otherwise)trim (where, set)foreac…

拆解Spring boot:Springboot为什么如此丝滑而简单?源码剖析解读自动装配

&#x1f389;&#x1f389;欢迎光临&#xff0c;终于等到你啦&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;持续更新的专栏《Spring 狂野之旅&#xff1a;从入门到入魔》 &a…

Screaming Frog SEO Spider:网站优化利器,轻松掌握网络爬虫精髓

在数字时代&#xff0c;网络爬虫已成为各行各业获取数据、分析趋势的重要工具。而在众多网络爬虫开发工具中&#xff0c;Screaming Frog SEO Spider以其强大的功能和易用性脱颖而出&#xff0c;成为众多网站优化师和SEO从业者的首选。 Screaming Frog SEO Spider是一款适用于M…

笔记本电脑数据恢复:如何轻松地从笔记本电脑恢复文件

不小心从笔记本电脑中删除了一些重要文件&#xff1f;或者恶意软件和其他不可控因素是否导致您的文件消失&#xff1f;人们很容易认为这些文件已经永远消失&#xff0c;并且无法恢复。但这与事实相差甚远。通过遵循正确的数据恢复礼仪并使用良好的数据恢复工具&#xff0c;您可…

英语翻译报价,千字英语翻译报价

众所周知&#xff0c;英语作为全球通用的语言&#xff0c;其翻译需求量极大。无论是欧美国家的日常交流&#xff0c;还是小语种的翻译工作&#xff0c;英语都常常作为中介语言&#xff0c;扮演着桥梁的角色。那么&#xff0c;英语翻译公司是如何定价的&#xff1f;每千字的英语…

Qt中进行客户端开发框架

在Qt中进行客户端开发是一种常见的做法&#xff0c;Qt是一个跨平台的C框架&#xff0c;提供了丰富的工具和类库&#xff0c;用于开发图形用户界面&#xff08;GUI&#xff09;应用程序、网络应用程序以及其他类型的软件。以下是一些常用的Qt客户端开发框架和技术&#xff0c;希…

Exam in MAC [容斥]

题意 思路 正难则反 反过来需要考虑的是&#xff1a; (1) 所有满条件一的(x,y)有多少对&#xff1a; x 0 时&#xff0c;有c1对 x 1 时&#xff0c;有c对 ...... x c 时&#xff0c;有1对 以此类推 一共有 (c2)(c1)/2 对 (2) 符合 x y ∈ S的有多少对&#xff1a…

Qt客户端开发的技术难点

在Qt客户端开发中&#xff0c;可能会遇到一些技术难点&#xff0c;这些难点可能与UI设计、性能优化、跨平台兼容性等方面有关。以下是一些可能的技术难点&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作…

虚拟游戏理财 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 在一款虚拟游戏中生活&#xff0c;你必须进行投资以增强在虚拟游戏中的资产以免被淘汰出局。 现有一家Bank&#xff0c;它提供有若干理财产品m&#xff0c;风险及…

将SQL数据库转换为Mysql数据库

一、准备工作 1、SQL server安装包与已经有数据的mdf、ldf数据库文件&#xff1b; 2、.net Framework安装包&#xff1b;&#xff08;用于支持SQL Server安装的组件&#xff09; 3、MySql安装包&#xff1b;&#xff08;用于目标数据库的环境安装&#xff09; 4、navicat安装包…

YOLOv8旋转目标检测实战:训练自己的数据集

课程链接&#xff1a;https://edu.csdn.net/course/detail/39393 旋转目标检测是计算机视觉领域的一个高级任务&#xff0c;它在传统目标检测的基础上进一步发展。传统目标检测技术主要关注于识别和定位图像中的物体&#xff0c;通常以水平边界框(HBB)来标识目标物体的位置。而…

SpringBoot高级

1.自动配置-Condition Condition是Spring4.0后引入的条件化配置接口&#xff0c;通过实现Condition接口可以完成有条件的加载相应的Bean 进入 SpringBoot 启动类&#xff0c;点击进入 run() 可以看到这个方法是有返回值的&#xff0c;返回值为 ConfigurableApplicationConte…

[Redis]——主从同步原理(全量同步、增量同步)

目录 Redis集群&#xff1a; 主从同步原理&#xff1a; replid和offset: 全量同步和增量同步&#xff1a; repl_baklog文件&#xff1a; 主从集群的优化&#xff1a; Redis集群&#xff1a; 部署多台Redis我们称之为Redis集群&#xff0c;他有一个主节点(负责写操作)&…

什么是施密特触发器?一文详解

施密特触发器的定义 施密特触发器&#xff08;Schmitt Trigger&#xff09;是一种电子电路&#xff0c;常用于数字逻辑电路和信号处理电路中。它具有两个不同的阈值电压级别&#xff0c;通过这些不同的电压级别&#xff0c;可以将输入信号转换为相对稳定的输出信号。 当输入信…

【Datawhale组队学习:Sora原理与技术实战】使用KAN-TTS合成女生沪语音频

Sambert-Hifigan模型介绍 拼接法和参数法是两种Text-To-Speech(TTS)技术路线。近年来参数TTS系统获得了广泛的应用&#xff0c;故此处仅涉及参数法。 参数TTS系统可分为两大模块&#xff1a;前端和后端。 前端包含文本正则、分词、多音字预测、文本转音素和韵律预测等模块&am…

Django之Form组件

Django之Form组件 目录 Django之Form组件介绍手动渲染错误信息基于Form组件校验数据重写错误信息用户名与密码radioSelect单选Select多选Select单选checkbox多选checkbox 前端渲染 介绍 Form组件提供了一种在网页上收集用户输入数据并将其提交到服务器进行处理的机制&#xff…

实战纪实 | 记一次绕过宝塔的的文件上传

前几天找到个可以上传任意文件的上传点&#xff0c;成功上传phpinfo页面并能访问&#xff0c;但是不能成功上传一句话&#xff0c;发现这台主机装了宝塔&#xff0c;经过反复尝试终于成功上传一句话并连接。 0x01 漏洞发现 结果前期摸索&#xff0c;发现了一个上传点&#xff0…

Java中 常见的开源树库介绍

阅读本文之前请参阅------Java中 树的基础知识介绍 在 Java 中&#xff0c;有几种流行的开源树库&#xff0c;它们提供了丰富的树算法和高级操作&#xff0c;可以帮助开发者更高效地处理树相关的问题。以下是几种常见的 Java 树库及其特点和区别&#xff1a; JTree 特点…

一场“猜成绩”大赛:ArrayList vs. LinkedList

今天我们将带来一场精彩绝伦的较量——ArrayList对阵LinkedList。 ArrayList它就像是一张大桌子&#xff0c;可以容纳各种各样的物品。 ArrayList是一个动态数组&#xff0c;具有随机访问的能力&#xff0c;这意味着我们可以在O(1)的时间复杂度内访问任意位置的元素。 它还具…

从零开始的LLaMA-Factory的指令增量微调

大模型相关目录 大模型&#xff0c;包括部署微调prompt/Agent应用开发、知识库增强、数据库增强、知识图谱增强、自然语言处理、多模态等大模型应用开发内容 从0起步&#xff0c;扬帆起航。 大模型应用向开发路径及一点个人思考大模型应用开发实用开源项目汇总大模型问答项目…