Java String详解(二)

news2025/2/27 17:26:01

上一篇博客:Java String详解(一)

 写在前面:大家好!我是晴空๓。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正,感谢大家的不吝赐教。我的唯一博客更新地址是:https://ac-fun.blog.csdn.net/。非常感谢大家的支持。一起加油,冲鸭!
用知识改变命运,用知识成就未来!加油 (ง •̀o•́)ง (ง •̀o•́)ง

文章目录

  • 前言
  • substring()截取字符串的子串
  • 连接字符串
    • 使用 + 进行连接

前言

 在上一篇博客Java String详解(一)中主要讲了String类的声明、字符串存储的位置以及String的不可变性。本篇主要写一下关于String的常用方法以及一些注意点。

substring()截取字符串的子串

 String类的 substring 方法可以从一个较大的字符串中提取出一个子串。通过查看String.java类可以发现一共有两种截取子串的方法:

public String substring(int beginIndex)
public String substring(int beginIndex, int endIndex)

 对于这个方法主要注意的是 substring() 是从 0 开始的;截取的子字符串包含 beginIndex 坐标的字符,但是不包含 endIndex 的字符(前闭后开式[))。通过substring()的源码就可以看到 substring() 会返回一个新的字符串对象,而不是修改了原有的字符串。这也是String不可变的一个体现:

public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }

连接字符串

使用 + 进行连接

 Java 语言允许使用 + 号拼接两个字符串,应用于 String++=Java 中仅有的被重载的操作符,Java 不允许程序员重载其他操作符。我们可以使用 JDK 自带的 javap 工具反编译一下以下使用 + 号进行连接字符串时发生了什么:

public class StringTest {

    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "world";
        String str = str1 + str2;
        System.out.println(str);
    }
}

使用 javac .\StringTest.java 编译代码之后再使用 javap -c .\StringTest.class 反编译.class文件,使用 -c 选项对代码进行反汇编,显示 Java 字节码的指令。可以看到如下字节码及相应的作用:

Compiled from "StringTest.java"
public class StringTest {
  public StringTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String hello
       2: astore_1
       3: ldc           #3                  // String world
       5: astore_2
       6: new           #4                  // class java/lang/StringBuilder
       9: dup
      10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
      13: aload_1
      14: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      17: aload_2
      18: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      21: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      24: astore_3
      25: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      28: aload_3
      29: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      32: return
}

ldc 命令是从常量池中加载各种类型的常量,包括字符串常量、整数常量、浮点数常量,甚至类引用等。对于字符串常量,ldc 指令的行为如下:
  1. 从常量池加载字符串:ldc 首先检查字符串常量池中是否已经有内容相同的字符串对象。
  2. 复用已有字符串对象:如果字符串常量池中已经存在内容相同的字符串对象,ldc 会将该对象的引用加载到操作数栈上。
  3. 没有则创建新对象并加入常量池:如果字符串常量池中没有相同内容的字符串对象,JVM 会在常量池中创建一个新的字符串对象,并将其引用加载到操作数栈中。

new 命令是创建一个新的对象,指令后面紧跟着指向常量池中的索引值,该索引值指向一个类符号引用,即类的全限定名。

invokevirtual 命令是 JVM 字节码用于调用对象实例方法的指令

 从以上字节码我们可以看出 java 中使用 + 拼接字符串本质上是通过 StringBuilder 调用 append() 方法实现的,拼接完成之后调用 toString() 得到一个 String 对象 。这里需要注意的一个点就是当我们在循环内使用 “+” 对字符串进行拼接的话会有一个明显的缺陷,那就是会造成编译器创建多个 StringBuilder 对象。每进行一次循环就会创建一个 StringBuilder 对象。如下:

public class StringTest {

    public static void main(String[] args) {
        String[] arr = {"he", "llo", "wor" + "ld"};
        String str = "";
        for (int i = 0; i < arr.length; i++) {
            str += arr[i];
        }
        System.out.println(str);
    }
}

使用 javac 反编译之后可以看到字节码如下:

Compiled from "StringTest.java"
public class StringTest {
  public StringTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_3
       1: anewarray     #2                  // class java/lang/String
       4: dup
       5: iconst_0
       6: ldc           #3                  // String he
       8: aastore
       9: dup
      10: iconst_1
      11: ldc           #4                  // String llo
      13: aastore
      14: dup
      15: iconst_2
      16: ldc           #5                  // String world
      18: aastore
      19: astore_1
      20: ldc           #6                  // String
      22: astore_2
      23: iconst_0
      24: istore_3
      25: iload_3
      26: aload_1
      27: arraylength
      28: if_icmpge     58
      31: new           #7                  // class java/lang/StringBuilder
      34: dup
      48: invokevirtual #10                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      51: astore_2
      52: iinc          3, 1
      55: goto          25
      58: getstatic     #11                 // Field java/lang/System.out:Ljava/io/PrintStream;
      61: aload_2
      62: invokevirtual #12                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      65: return
}

 我们只需要关注 20~55 即可,相关的解释如下:

20: ldc #6 // String:加载空字符串。
22: astore_2:将其存储在局部变量 StringBuilder 引用。
23: iconst_0:将 0 压入栈(循环索引)。
24: istore_3:存储循环索引。
25: iload_3:加载循环索引。
26: aload_1:加载字符串数组引用。
27: arraylength:获取数组长度。
28: if_icmpge 58:如果循环索引大于等于数组长度,跳转到标签 58(结束循环)。
31: new #7 // class java/lang/StringBuilder:创建一个新的 StringBuilder 对象。
34: dup:复制 StringBuilder 对象引用。
48: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;:调用 StringBuilder 的 toString 方法。
51: astore_2:将结果字符串存储在局部变量 StringBuilder 引用。
52: iinc 3, 1:循环索引加 155: goto 25:跳转回循环开始。

 所以当我们需要在循环内进行字符串拼接时最好直接使用 StringBuilder 对象进行字符串拼接,这样就不会造成以上的问题。如果你使用的是 IDEA 的话,IDEA 自带的代码检查也会提示你修改代码
在这里插入图片描述

public class StringTest {

    public static void main(String[] args) {
        String[] arr = {"he", "llo", "wor" + "ld"};
        StringBuilder str = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            str.append(arr[i]);
        }
        System.out.println(str);
    }
}

未完待续……


  • 《大话Java性能优化》
  • 字符串拼接用 + 还是 stringbuilder
  • 还在无脑用 StringBuilder?来重温一下字符串拼接吧

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qt之点击鼠标右键创建菜单栏使用(六)

Qt开发 系列文章 - menu&#xff08;六&#xff09; 目录 前言 一、示例演示 二、菜单栏 1.MenuBar 2.Menu 总结 前言 QMainWindow是一个为用户提供主窗口程序的类&#xff0c;包含一个菜单栏&#xff08;menubar&#xff09;、多个工具栏(toolbars)、一个状态栏(status…

《拉依达的嵌入式\驱动面试宝典》—C/CPP基础篇(一)

《拉依达的嵌入式\驱动面试宝典》—C/CPP基础篇(一) 你好&#xff0c;我是拉依达。 感谢所有阅读关注我的同学支持&#xff0c;目前博客累计阅读 27w&#xff0c;关注1.5w人。其中博客《最全Linux驱动开发全流程详细解析&#xff08;持续更新&#xff09;-CSDN博客》已经是 Lin…

IntelliJ IDEA(2024版) 的安装、配置与使用教程:常用配置、创建工程等操作(很详细,你想要的都在这里)

IDEA的安装、配置与使用&#xff1a; Ⅰ、IDEA 的安装&#xff1a;1、IDEA 的下载地址(官网)&#xff1a;2、IDEA 分为两个版本&#xff1a;旗舰版 (Ultimate) 和 社区版 (Community)其一、两个不同版本的安装文件&#xff1a;其二、两个不同版本的详细对比&#xff1a; 3、IDE…

MybatisPlus-配置加密

配置加密 目前配置文件中的很多参数都是明文&#xff0c;如果开发人员发生流动&#xff0c;很容易导致敏感信息的泄露。所以MybatisPlus支持配置文件的加密和解密功能。 我们以数据库的用户名和密码为例。 生成秘钥 首先&#xff0c;我们利用AES工具生成一个随机秘钥&#…

深度学习基础--将yolov5的backbone模块用于目标识别会出现怎么效果呢??

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 yolov5网络结构比较复杂&#xff0c;上次我们简要介绍了yolov5网络模块&#xff0c;并且复现了C3模块&#xff0c;深度学习基础–yolov5网络结构简介&a…

数据结构---图(Graph)

图&#xff08;Graph&#xff09;是一种非常灵活且强大的数据结构&#xff0c;用于表示实体之间的复杂关系。在图结构中&#xff0c;数据由一组节点&#xff08;或称为顶点&#xff09;和连接这些节点的边组成。图可以用于表示社交网络、交通网络、网络路由等场景。 1. 基本概…

人工智能技术的深度解析与推广【人工智能的应用场景】

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c; 忍不住分享一下给大家。点击跳转到网站 学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把…

软件开发中 Bug 为什么不能彻底消除

在软件开发中&#xff0c;Bug无法彻底消除的原因主要包括&#xff1a;软件复杂度高、人员认知与沟通受限、需求和环境不断变化、工具与测试覆盖不足、经济与时间成本制约。其中“需求和环境不断变化”尤为关键&#xff0c;因为在实际开发中&#xff0c;业务逻辑随着市场与用户反…

【嵌入式软件】跑开发板的前置服务配置

在嵌入式开发中,通常需要在 开发板和主机之间共享、传输和挂载文件。 这篇文章是关于如何在 Ubuntu 中配置 Samba、TFTP 和 NFS 协议的详细步骤。这些协议分别用于远程文件共享、文件传输和内核挂载文件系统。 如何安装协议: 参考:ubuntu18配置:详细的内容我手写了一份文档。…

CTF 攻防世界 Web: FlatScience write-up

题目名称-FlatScience 网址 index 目录中没有发现提示信息&#xff0c;链接会跳转到论文。 目前没有发现有用信息&#xff0c;尝试目录扫描。 目录扫描 注意到存在 robots.txt 和 login.php。 访问 robots.txt 这里表明还存在 admin.php admin.php 分析 在这里尝试一些 sql…

从YOLOv5到训练实战:易用性和扩展性的加强

文章目录 前言一、模型介绍二、YOLOv5网络结构1.Input&#xff08;输入端&#xff09;&#xff1a;智能预处理与优化策略2.Backbone&#xff08;骨干网络&#xff09;&#xff1a;高效特征提取3.NECK&#xff08;颈部&#xff09;&#xff1a;特征增强与多尺度融合4.Prediction…

Ilya Sutskever发表了对AI未来发展的颠覆性看法

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Crawl4AI:一个为大型语言模型(LLM)和AI应用设计的网页爬虫和数据提取工具实战

这里写目录标题 一、crawl4AI功能及简介1、简介2、特性 二、项目地址三、环境安装四、大模型申请五、代码示例1.生成markdown2.结构化数据 一、crawl4AI功能及简介 1、简介 Crawl4AI 是一个开源的网页爬虫和数据抓取工具&#xff0c;一个python项目&#xff0c;主要为大型语言…

HuLa——一款基于 Tauri+Vue3 构建的桌面即时通讯应用

文章目录 一、HuLa简介二、技术栈介绍三、安装运行四、界面体验五、开源地址 一、HuLa简介 HuLa 是一个基于 Tauri、Vite 5、Vue 3 和 TypeScript 构建的即时通讯系统。它利用了 Tauri 的跨平台能力和 Vue 3 的响应式设计&#xff0c;结合了 TypeScript 的类型安全特性和 Vite…

websocket_asyncio

WebSocket 和 asyncio 指南 简介 本指南涵盖了使用 Python 中的 websockets 库进行 WebSocket 编程的基础知识&#xff0c;以及 asyncio 在异步非阻塞 I/O 中的作用。它提供了构建高效 WebSocket 服务端和客户端的知识&#xff0c;以及 asyncio 的特性和优势。 1. 什么是 WebS…

《Java核心技术I》Swing用户界面组件

Swing和模型-视图-控制器设计模式 用户界面组件各个组成部分&#xff0c;如按钮&#xff0c;复选框&#xff0c;文本框或复杂的树控件&#xff0c;每个组件都有三个特征&#xff1a; 内容&#xff0c;如按钮的状态&#xff0c;文本域中的文本。外观&#xff0c;颜色&#xff0c…

如何通过递延型指标预测项目的长期成果?

递延型指标&#xff08;Deferred Metrics&#xff09;是指那些并不立即反映或直接影响当前操作、决策或行为的指标&#xff0c;而是随着时间的推移&#xff0c;才逐渐显现出影响效果的指标。这类指标通常会在一段时间后反映出来&#xff0c;或者需要一定的周期才能展现其成果或…

uni-app开发AI康复锻炼小程序,帮助肢体受伤患者康复!

**提要&#xff1a;**近段时间我们收到多个康复机构用户&#xff0c;咨询AI运动识别插件是否可以应用于肢力运动受限患者的康复锻炼中来&#xff0c;插件是可以应用到AI康复锻炼中的&#xff0c;今天小编就为您介绍一下AI运动识别插件在康腹锻炼中的应用场景。 一、康复机构的应…

C++(十八)

前言&#xff1a; 本文依据上一篇&#xff0c;继续对C中的函数进行学习。 一&#xff0c;内联函数。 再执行函数代码时&#xff0c;比不使用函数花费了更多时间&#xff0c;因为总结步骤&#xff0c;传递参数和返回值都很花费时间。 因此&#xff0c;在调试小型函数时&…

如何在 Ubuntu 上安装 NodeBB 并使用 Nginx 反向代理

简介 NodeBB 是一款基于 Node.js 的开源论坛软件&#xff0c;为在线社区提供了现代化和响应式的解决方案。在 Ubuntu Linux 上运行的 NodeBB 利用了操作系统的强大性和灵活性&#xff0c;以提供高性能和可扩展性。它结合了 MongoDB 或 Redis 进行数据库管理&#xff0c;使其能…