Java字符串:构建和操作字符序列的动态工具

在这里插入图片描述

  • 👑专栏内容:Java
  • ⛪个人主页:子夜的星的主页
  • 💕座右铭:前路未远,步履不停

目录

  • 一、常用方法
    • 1、字符串构造
    • 2、String对象的比较
      • Ⅰ、`==`比较是否引用同一个对象
      • Ⅱ、 按照字典序比较
    • 3、转换
      • Ⅰ、数值和字符串的转换
      • Ⅱ、大小写转换
      • Ⅲ、字符串转数组
      • Ⅳ、格式化
    • 4、字符串替换
    • 5、字符串拆分
    • 6、字符串截取
    • 7、其他方法
    • 8、字符串的不可变性
    • 9、字符串修改
  • 二、StringBuilder和StringBuffer
    • 1、用法
    • 2、问题


一、常用方法

String类是Java标准库中的一个核心类,用于表示字符串。字符串是一系列字符的集合。在Java中,String对象是不可变的,这意味着一旦创建了一个String对象,其内容就不能被更改。String类提供了许多实用方法,可以方便地操作和处理字符串。

查询文档:字符串官方文档

1、字符串构造

String类提供的构造方式非常多,常用的就以下三种:

public static void main(String[] args) {
    // 使用常量串构造
    String s1 = "hello";
    System.out.println(s1);
    // 直接newString对象
    String s2 = new String("hello");
    System.out.println(s1);
    // 使用字符数组进行构造
    char[] array = {'h','e','l','l','o'};
    String s3 = new String(array);
    System.out.println(s1);
}

String是引用类型,内部并不存储字符串本身,在String类的实现源码中,String类实例变量如下:

image-20230712111105930

public static void main(String[] args) {
    // s1和s2引用的是不同对象 s1和s3引用的是同一对象
    String s1 = new String("hello");
    String s2 = new String("world");
    String s3 = s1;
    System.out.println(s1.length()); // 获取字符串长度---输出5
    System.out.println(s1.isEmpty()); // 如果字符串长度为0,返回true,否则返回false
}

image-20230712111318654

在Java中“”引起来的也是String类型对象。

// 打印"hello"字符串(String对象)的长度
System.out.println("hello".length());

2、String对象的比较

Ⅰ、==比较是否引用同一个对象

注意:对于内置类型,==比较的是变量中的值;对于引用类型==比较的是引用中的地址。

public static void main(String[] args) {
    int a = 10;
    int b = 20;
    int c = 10;
    // 对于基本类型变量,==比较两个变量中存储的值是否相同
    System.out.println(a == b); // false
    System.out.println(a == c); // true
    // 对于引用类型变量,==比较两个引用变量引用的是否为同一个对象
    String s1 = new String("hello");
    String s2 = new String("hello");
    String s3 = new String("world");
    String s4 = s1;
    System.out.println(s1 == s2); // false
    System.out.println(s2 == s3); // false
    System.out.println(s1 == s4); // true
}

Ⅱ、 按照字典序比较

字典序:字符大小的顺序

String类重写了父类Object中equals方法,Object中equals默认按照==比较,String重写equals方法后,按照如下规则进行比较,比如: s1.equals(s2)

public boolean equals(Object anObject) {
    // 1. 先检测this 和 anObject 是否为同一个对象比较,如果是返回true
    if (this == anObject) {
        return true;
    }
    // 2. 检测anObject是否为String类型的对象,如果是继续比较,否则返回false
    if (anObject instanceof String) {
        // 将anObject向下转型为String类型对象
        String anotherString = (String)anObject;
        int n = value.length;
        // 3. this和anObject两个字符串的长度是否相同,是继续比较,否则返回false
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            // 4. 按照字典序,从前往后逐个字符进行比较
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}
public class Main {
    public static void main(String[] args) {
        String s1 = new String("hello");
        String s2 = new String("hello");
        String s3 = new String("Hello");

        // s1、s2、s3 引用的是三个不同对象,因此 == 比较结果全部为 false
        System.out.println(s1 == s2); // false
        System.out.println(s1 == s3); // false

        // equals 比较:String 对象中的逐个字符
        // 虽然 s1 与 s2 引用的不是同一个对象,但是两个对象中放置的内容相同,因此输出 true
        // s1 与 s3 引用的不是同一个对象,而且两个对象中内容也不同,因此输出 false
        System.out.println(s1.equals(s2)); // true
        System.out.println(s1.equals(s3)); // false
    }
}

3、转换

Ⅰ、数值和字符串的转换

public static void main(String[] args) {
    // 数字转字符串
    String s1 = String.valueOf(1234);
    String s2 = String.valueOf(12.34);
    String s3 = String.valueOf(true);
    String s4 = String.valueOf(new Student("Hanmeimei", 18));
    System.out.println(s1);
    System.out.println(s2);
    2. 大小写转换
    3. 字符串转数组
    4. 格式化
    2.5 字符串替换
    使用一个指定的新的字符串替换掉已有的字符串数据,可用的方法如下:
    System.out.println(s3);
    System.out.println(s4);
    System.out.println("=================================");
    // 字符串转数字
    // 注意:Integer、Double等是Java中的包装类型,这个后面会讲到
    int data1 = Integer.parseInt("1234");
    double data2 = Double.parseDouble("12.34");
    System.out.println(data1);
    System.out.println(data2);
}

Ⅱ、大小写转换

public static void main(String[] args) {
    String s1 = "hello";
    String s2 = "HELLO";
    // 小写转大写
    System.out.println(s1.toUpperCase());
    // 大写转小写
    System.out.println(s2.toLowerCase());
}

Ⅲ、字符串转数组

public static void main(String[] args) {
    String s = "hello";
    // 字符串转数组
    char[] ch = s.toCharArray();
    for (int i = 0; i < ch.length; i++) {
    	System.out.print(ch[i]);
    }
    System.out.println();
    // 数组转字符串
    String s2 = new String(ch);
    System.out.println(s2);
}

Ⅳ、格式化

public static void main(String[] args) {
    String s = String.format("%d-%d-%d", 2019, 9,14);
    System.out.println(s);
}

4、字符串替换

使用一个指定的新的字符串替换掉已有的字符串数据,可用的方法如下:

方法功能
String replaceAll(String regex, String replacement)替换所有的指定内容
String replaceFirst(String regex, String replacement)替换首个内容
String str = "helloworld" ;
System.out.println(str.replaceAll("l", "_"));
System.out.println(str.replaceFirst("l", "_"));

注意事项: 由于字符串是不可变对象, 替换不修改当前字符串, 而是产生一个新的字符串

5、字符串拆分

可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。

方法功能
String[] split(String regex)将字符串全部拆分
String[] split(String regex, int limit)将字符串以指定的格式,拆分为limit组
//实现字符串的拆分处理
String str = "hello world " ;
String[] result = str.split(" ") ; // 按照空格拆分
for(String s: result) {
	System.out.println(s);
}
//实现字符串部分拆分
String str = "hello world " ;
String[] result = str.split(" ",2) ;
for(String s: result) {
	System.out.println(s);
}

拆分是特别常用的操作,另外有些特殊字符作为分割符可能无法正确切分, 需要加上转义。

//拆分ip地址
String str = "192.168.1.1" ;
String[] result = str.split("\\.") ;
for(String s: result) {
System.out.println(s);
}

【注意事项】

  1. 字符"|“,”*“,”+"都得加上转义字符,前面加上 “\”

  2. 而如果是 “” ,那么就得写成 “\\”

  3. 如果一个字符串中有多个分隔符,可以用"|"作为连字符

//多次拆分
String str = "name=zhangsan&age=18" ;
String[] result = str.split("&") ;
for (int i = 0; i < result.length; i++) {
    String[] temp = result[i].split("=") ;
    System.out.println(temp[0]+" = "+temp[1]);
}

6、字符串截取

从一个完整的字符串之中截取出部分内容。可用方法如下:

方法功能
String substring(int beginIndex)从指定索引截取到结尾
String substring(int beginIndex, int endIndex)截取部分内容
// 观察字符串截取
String str = "helloworld" ;
System.out.println(str.substring(5));
System.out.println(str.substring(0, 5));

【注意事项】

  1. 索引从0开始

  2. 注意前闭后开区间的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标

7、其他方法

方法功能
String trim()去掉字符串中的左右空格,保留中间空格
String toUpperCase()字符串转大写
String toLowerCase()字符串转小写
// 观察trim()方法的使用
String str = " hello world " ;
System.out.println("["+str+"]");
System.out.println("["+str.trim()+"]");

trim 会去掉字符串开头和结尾的空白字符(空格, 换行, 制表符等)

// 大小写转换
String str = " hello%$$%@#$%world 哈哈哈 " ;
System.out.println(str.toUpperCase());
System.out.println(str.toLowerCase());
//这两个函数,只转换字母

8、字符串的不可变性

String是一种不可变对象. 字符串中的内容是不可改变。字符串不可被修改,是因为:

  • String类在设计时就是不可改变的,String类实现描述中已经说明了

image-20230712175939416

image-20230712175944660

String类被final修饰,表明该类不能被继承。value被修饰被final修饰,表明value自身的值不能改变,即不能引用其它字符数组,但是其引用空间中

的内容可以修改。

  • 所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象

比如 replace 方法:

image-20230712180155564

【问题】字符串不可变是因为其内部保存字符的数组被final修饰了,因此不能改变。这样的说法对吗?

这种说法是错误的,不是因为String类自身,或者其内部value被final修饰而不能被修改。final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内容是可以修改的。

public static void main(String[] args) {
    final int array[] = {1,2,3,4,5};
    array[0] = 100;
    System.out.println(Arrays.toString(array));
    // array = new int[]{4,5,6}; // 编译报错:Error:(19, 9) java: 无法为最终变量array分配值
}

【问题】为什么String要设计成不可变的?(不可变对象的好处是什么?)

  1. 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑写时拷贝的问题了

  2. 不可变对象是线程安全的

  3. 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中

9、字符串修改

注意:尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率非常低下。

public static void main(String[] args) {
    String s = "hello";
    s += " world";
    System.out.println(s); // 输出:hello world
}

但是这种方式不推荐使用,因为其效率非常低,中间创建了好多临时对象。

image-20230712180730281

public static void main(String[] args) {
    long start = System.currentTimeMillis();
    String s = "";
    for(int i = 0; i < 10000; ++i){
    	s += i;
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
    start = System.currentTimeMillis();
    StringBuffer sbf = new StringBuffer("");
    for(int i = 0; i < 10000; ++i){
    	sbf.append(i);
    }
    end = System.currentTimeMillis();
    System.out.println(end - start);
    start = System.currentTimeMillis();
    StringBuilder sbd = new StringBuilder();
    for(int i = 0; i < 10000; ++i){
    	sbd.append(i);
    }
    end = System.currentTimeMillis();
    System.out.println(end - start);
}

可以看待在对String类进行修改时,效率是非常慢的,因此:尽量避免对String的直接需要,如果要修改建议尽量使用StringBuffer或者StringBuilder

二、StringBuilder和StringBuffer

1、用法

由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilderStringBuffer类。

参考文档:https://docs.oracle.com/javase/8/docs/api/

方法说明
append(String str)在尾部追加,相当于String的+=,可以追加多种数据类型
charAt(int index)获取index位置的字符
length()获取字符串的长度
capacity()获取底层保存字符串空间总的大小
ensureCapacity(int minimumCapacity)确保容量至少等于指定的最小值
setCharAt(int index, char ch)将index位置的字符设置为ch
indexOf(String str)返回str第一次出现的位置
indexOf(String str, int fromIndex)从fromIndex位置开始查找str第一次出现的位置
lastIndexOf(String str)返回最后一次出现str的位置
lastIndexOf(String str, int fromIndex)从fromIndex位置开始找str最后一次出现的位置
insert(int offset, String str)在offset位置插入多种数据类型
deleteCharAt(int index)删除index位置字符
delete(int start, int end)删除[start, end)区间内的字符
replace(int start, int end, String str)将[start, end)位置的字符替换为str
substring(int start)从start开始一直到末尾的字符以String的方式返回
substring(int start, int end)将[start, end)范围内的字符以String的方式返回
reverse()反转字符串
toString()将所有字符按照String的方式返回
public static void main(String[] args) {
    StringBuilder sb1 = new StringBuilder("hello");
    StringBuilder sb2 = sb1;
    // 追加:即尾插-->字符、字符串、整形数字
    sb1.append(' '); // hello
    sb1.append("world"); // hello world
    sb1.append(123); // hello world123
    System.out.println(sb1); // hello world123
    System.out.println(sb1 == sb2); // true
    System.out.println(sb1.charAt(0)); // 获取0号位上的字符 h
    System.out.println(sb1.length()); // 获取字符串的有效长度14
    System.out.println(sb1.capacity()); // 获取底层数组的总大小
    sb1.setCharAt(0, 'H'); // 设置任意位置的字符 Hello world123
    sb1.insert(0, "Hello world!!!"); // Hello world!!!Hello world123
    System.out.println(sb1);
    System.out.println(sb1.indexOf("Hello")); // 获取Hello第一次出现的位置
    System.out.println(sb1.lastIndexOf("hello")); // 获取hello最后一次出现的位置
    sb1.deleteCharAt(0); // 删除首字符
    sb1.delete(0,5); // 删除[0, 5)范围内的字符
    String str = sb1.substring(0, 5); // 截取[0, 5)区间中的字符以String的方式返回
    System.out.println(str);
    sb1.reverse(); // 字符串逆转
    str = sb1.toString(); // 将StringBuffer以String的方式返回
    System.out.println(str);
}

从上述例子可以看出:StringStringBuilder最大的区别在于String的内容无法修改,而StringBuilder的内容可以修改

频繁修改字符串的情况考虑使用StringBuilder

注意:StringStringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:

  • String变为StringBuilder: 利用StringBuilder的构造方法或append()方法

  • StringBuilder变为String: 调用toString()方法。

2、问题

【问题1】String、StringBuffer、StringBuilder的区别?

  • String的内容不可修改,StringBufferStringBuilder的内容可以修改

  • StringBufferStringBuilder大部分功能是相似的

  • StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作

【问题2】 以下总共创建了多少个String对象【前提不考虑常量池之前是否存在】

String str = new String("ab"); 
String str = new String("a") + new String("b");
String str = new String("ab");

这行代码会创建两个 String 对象:
一个是字符串字面量 “ab”,这个字符串会被存储在字符串常量池中。
另一个是使用 new String("ab") 创建的 String 对象。

String str = new String("a") + new String("b");

这行代码会创建五个 String 对象:一个是字符串字面量 “a”,这个字符串会被存储在字符串常量池中。
一个是使用 new String("a") 创建的 String 对象。
一个是字符串字面量 “b”,这个字符串会被存储在字符串常量池中。
一个是使用 new String("b") 创建的 String 对象。
最后一个是由 new String("a")new String("b")连接起来的新的 String 对象。

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

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

相关文章

探索 OceanBase 中图数据的实现

在数据管理和处理的现代环境中&#xff0c;对能够处理复杂数据结构的复杂数据模型和方法的需求从未如此迫切。图数据的出现以其自然直观地表示复杂关系的独特能力&#xff0c;开辟了数据分析的新领域。 虽然 Neo4j 等成熟的图形数据库为处理图形数据提供了强大的解决方案&…

HTML 使用 ruby 给汉字加拼音

使用 ruby 给汉字加拼音 兼容性 使用 ruby 给汉字加拼音 大家有没有遇到过要给汉字头顶上加拼音的需求? 如果有的话, 你是怎么解决的呢? 如果费尽心思, 那么你可能走了很多弯路, 因为 HTML 原生就有这样的标签来帮我们实现类似的需求. <ruby> ruby 本身是「红宝石」…

K8S陈述式资源管理(1)

命令行: kubectl命令行工具 优点: 90%以上的场景都可以满足对资源的增&#xff0c;删&#xff0c;查比较方便&#xff0c;对改不是很友好 缺点:命令比较冗长&#xff0c;复杂&#xff0c;难记声明式 声明式&#xff1a;K8S当中的yaml文件来实现资源管理 GUI&#xff1a;图形…

C#,入门教程(08)——基本数据类型及使用的基础知识

上一篇&#xff1a; C#&#xff0c;入门教程(07)——软件项目的源文件与目录结构https://blog.csdn.net/beijinghorn/article/details/124139947 数据类型用于指定数据体&#xff08;DataEntity&#xff0c;包括但不限于类或结构体的属性、变量、常量、函数返回值&#xff09;…

3_并发编程可见性(volatile)之缓存锁内存屏障过程

并发编程可见性volatile 1.背景原来 从下面的程序可以知道main线程把stop修改成false&#xff0c;而在t1线程没有中没有读取到stop值为false&#xff0c;所以导致了t1线程不能够停止。 从而说明stop值在线程t1不可见&#xff0c;解决这个问题在stop变量上添加volatile即可(p…

java spring boot 获取resource目录下的文档

主要代码 String filePath"templates/test.xls" ClassPathResource classPathResource new ClassPathResource(filePath); InputStream inputStream classPathResource.getInputStream();目录 主要目录存放再这 代码案例 public void downloadTemplate( HttpS…

计算机毕业设计 基于SpringBoot的公司资产网站的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

rhino犀牛怎么导入和调整背景图?

rhino犀牛怎么导入和调整背景图&#xff1f;Rhino建模过程中经常要用到背景图&#xff0c;为了更加方便快捷&#xff0c;我们会直接导入一些图片来当做背景&#xff0c;那么Rhino犀牛如何导入和调整背景图呢&#xff0c;让我们一起来看看吧 打开犀牛软件&#xff0c;进入操作界…

玩转Mysql 二(MySQL的目录结构与表结构)

一路走来,所有遇到的人,帮助过我的、伤害过我的都是朋友,没有一个是敌人。 一、MYSQL目录结构及命令存放路径 1、查看MYSQL数据文件存放路径 mysql> show variables like datadir; 注意:生成环境要提前规划好数据存放目录,存储一般以T为单位闪盘。 2、MYSQL命令存放…

Android两个APP之间跳转+手机图标修改

APP之间跳转 两个APP之间跳转同样使用Intent进行跳转&#xff0c;将需要跳转的APP都下载到手机中&#xff0c;通过主APP调用需要跳转的APP包名进行跳转。 最好在其中加上try-catch语句&#xff0c;当需要跳转的APP不存在时进行错误抓取。 代码如下&#xff1a; Intent mInten…

iview inputNumber有一个默认值1,来看解决方案

iview inputNumber为什么总有一个默认值1&#xff0c;怎么让它为空。 修改编辑没问题&#xff0c;赋值都没问题&#xff0c;但是新增的时候会有默认值1&#xff0c;也没赋值 这种情况你要手动解决&#xff0c;看看当前值有没有被覆盖 我这个问题就是出现覆盖导致的 看代码似乎…

生信技能33 - gnomAD数据库hg19/hg38 VCF文件批量下载脚本

gnomAD数据库下载地址 gnomAD downloads gnomAD v2.1.1数据集包含来自125,748个外显子组和15,708个全基因组的数据,所有这些数据都映射到GRCh 37/hg 19和GRCh 38/hg 38 两个版本的参考序列。 gnomAD数据库hg19与hg39 VCF文件批量下载脚本 download.sh # 获取当前目录路径…

STM32 IAP学习

STM32三种烧录方式 ISP&#xff1a;In System Programming&#xff08;在系统编程&#xff09; 执行芯片厂商的BootLoader程序进入ISP模式&#xff0c;进入ISP模式后&#xff0c;用户可选择官方提供的烧录通信接口&#xff08;如&#xff1a;串口&#xff09;&#xff0c;并配…

机械配件移动商城课程概述

项目介绍 开发准备 任务 开源库介绍 框架搭建 工具类

单机部署Rancher

上次已经安装完毕了k8s了&#xff0c;但是想要界面化的管理&#xff0c;离不开界面工具&#xff0c;首推就是rancher&#xff0c;本文介绍安装rancher的安装&#xff0c;也可以将之前安装的k8s管理起来。 已经安装完毕docker和docker-ce的可以直接从第三部分开始。 一、基础准…

Rockchip平台双屏异显功能实现(基于Android13)

Rockchip平台双屏异显功能实现(基于Android13) 1. 异显实现方案 Rockchip SDK平台支持两种不同的异显方案&#xff1a;Android Presentation和Android Activity指定屏幕启动。 使用Android Presentation方案&#xff0c;需要在APP开发中调用相应接口以使指定视图&#xff08…

Debezium发布历史49

原文地址&#xff1a; https://debezium.io/blog/2019/02/19/reliable-microservices-data-exchange-with-the-outbox-pattern/ 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. 使用发件箱模式进行可靠的微服务数…

FSMC驱动LCD

FSMC( Flexible static memory controller)全称“灵活的静态存储器控制器”&#xff0c;是 STM32中一个很有特色的外设&#xff0c;通过 FSMC&#xff0c;STM32可以通过FSMC与SRAM、ROM、PSRAM、Nor Flash和NandFlash存储器的引脚相连&#xff0c;从而进行数据的交换。 FSMC的本…

Java面试项目推荐,异构数据源数据流转服务DatalinkX

前言 作为一个年迈的夹娃练习生&#xff0c;每次到了春招秋招面试实习生时都能看到一批简历&#xff0c;十个简历里得有七八个是写商城或者外卖项目。 不由得想到了我大四那会&#xff0c;由于没有啥项目经验&#xff0c;又想借一个质量高点的项目通过简历初筛&#xff0c;就…

LeetCode 2221. 数组的三角和

文章目录 1. 题目 2. 解题 1. 题目 给你一个下标从 0 开始的整数数组 nums ,其中 nums[i] 是 0 到 9 之间(两者都包含)的一个数字。 nums 的 三角和 是执行以下操作以后最后剩下元素的值: nums 初始包含 n 个元素。如果 n == 1 ,终止 …