当前位置: 首页 > news >正文

Javase 之 字符串String类

一、String 类

1.1、什么是String类?

  • 我们知道 String 定义出来的 引用是用来存字符串的,也就是说和字符串有关系
    在这里插入图片描述
  • 我们看到String类的内部有个 private final byte 修饰的value数组,也就是说,我们传2进去的字符串是这个数组接收的。那就有疑惑了,传入数字用这个数组接收我没话说,但是 char 类型的字符,他怎么接收呢?我们知道,字符是 ascii 值。所以这个数组存的是字符的 ascii 值。
  • final 修饰说明 value ,只能定义的同时初始化,并且 value 只能指向一个对象,就是我们初始化的对象
// 此时说明value只指向abc这个对象,如果想改为value这个引用指向别的对象,是不允许的,因为是final修饰public final byte[] value = {"abc"}// 错误代码value = {"def"}
  • 但是还有一个问题,就是可以在外部改变字符串内部的内容
 // 如果value 是public final修饰的话,虽然value不能指向别的对象,但是可以可以改变字符串的内容value[0] = c;
  • 为了解决这个问题,就使用了private 修饰,限定他只能在String类中使用

1.2、String类的语法

  • 我们也是知道,String 是引用类型,也就是说可以new对象的
//方法一:直接赋值String str1 = "abc"//方法二:实例化对象String str2 = new String"abc";
  • 这两种初始化在内存中存储的方式不一样,细节看字符串存储内存
  • string类还有很多构造方法,细节去看String类的源码

1.3、什么是池?

  • 池就是一个容器,专门用来装常用的量。
  • 比如说老妈给生活费,有的会一个月一个月的给到你微信上面,有的会直接给一个学期的生活费存到一个银行卡上。池就好像给一个学期的生活费存到银行卡那样。你需要使用了,直接去银行卡拿来用就行

1.3.1、字符串常量池

  • 字符串常量池,是用来存储常用的字符串的。
  • 当你使用String类new对象存储字符串时,String首先是去字符串常量池中看一下有没有和你要定义的字符串一样的,如果有,就直接拿来使用(即直接存储在常量池中一样的字符串的地址),如果没有,那么他就会把你要定义的字符串存到字符串常量池中

1.4、字符串内存存储

  • 第一种
String str1 = new String"abc";
String str2 = "abc";

他的内存如下图

在这里插入图片描述

  • 定义 str1 时,首先到常量池中看一下有没有abc 这个字符串,发现没有,所以就把abc存到常量池中
  • 当定义str2 时,首先带常量池中看一下有没有abc这个字符串,发现有,所以直接就把常量池中abc字符串的地址存到str2中
  • 第二种
  String str1 = "abc";String str2 = "abc";

在这里插入图片描述

  • 这种也是一样,当初始化str1 时,String首先去常量池中看一下有没有abc,发现没有,所以就把abc存在常量池中
  • 当 定义 str2 并初始化时,String首先去常量池中看一下有没有abc,发现有,就直接把abc字符串的地址给了str2
  • 第3种
String str1 = new String();
String str2 = new String();

在这里插入图片描述

  • 这总硬要new对象的,和上面的存储的不一样,但是原理还是一样的,String也是会对abc进行在常量池中查找,发现没有,就把abc存在常量池中
  • 当str2 硬要new对象时,String也会去常量池中检查是否有abc ,发现有,就把abc的地址存到str2 的对象的value数组中。这点和上面的有区别

二、常用方法

2.1、equals方法

  • 是用来比较两个字符串是否相同,返回值是boolean类型

2.2、compareTo方法

  • 这个是从Comparable接口中重写的方法,说明String实现了 Comparable接口,这个也是比较两个字符串是否相等的,返回值是 int 类型

2.3、compareToIgnoreCase方法

  • 这个也是用来比较两个字符串是否一样的,但是他是忽略大小写进行比较

2.4、字符串查找

2.4.1、char charAt(int index)方法

  • 是用来返回第index个下标的字符

2.4.2、int indexOf (int ch)方法

  • 传参传的是字符,返回第一次出现该字符的下标
  • 默认从0下标开始找
  • 因为字符是asicii值,所以用int 接收

2.4.3、int indexOf(int ch ,int fromIndex)方法

  • 传参传的是字符和 需要开始找的下标
  • 从 fromIndex 下标开始找,返回第一次出现该字符的下标

2.4.4、int indexOf (String str)方法

  • 传的是字符串
  • 默认从0开始找,找到第一次出现的这个字符串,并返回找到的字符串的第一个字符的下标

2.4.5、int indexOf (String str ,int fromIndex)方法

  • 传的是字符串,和开始找位置的下标
  • 从 fromIndex 下标开始找,找到第一次出现的这个字符串,并返回找到的字符串的第一个字符的下标

2.4.6、int lastIndexOf(int ch)方法

  • 传的是要找的字符
  • 从字符串的后往前找,找到返回第一次出现该字符的下标

2.4.7、int lastIndexOf(int ch,int fromIndex)方法

  • 传的是要找的字符和从哪个下标开始往前找
  • 从fromIndex这个下标,从后往前找,找到返回第一次出现的下标

2.4.8、int lastIndexOf(String str)方法

  • 传参传的是字符串
  • 从后往前找,找到第一次出现该字符串,就返回该字符串的第一个字符的下标

2.4.9、int lastIndexOf(String str ,int fromIndex)方法

  • 传参传的是字符串和,开始找的起始下标
  • 从 fromIndex 这个下标从后往前找,找到第一次出现该字符串,就返回该字符串的第一个字符的下标

2.5、转换

2.5.1、数值和字符串之间的转换

2.5.1.1、数值转字符串 valueOf
  • 作用是 把一个数 (整,浮点)转为字符串
  • 所以他的返回值是一个字符串
  • 这个方法在String 类源码中看,他是static修饰的,也就是说他是类方法只能类 加 点调用
String str1 = String.valueOf(1234);

把数值1234 转换为字符串1234

2.5.1.2、字符串转数值 parseInt
  • 作用是 把一个字符串,转为数值(整、浮点)
  • 所以他返回的是一个数
  • 这个方法在int 的包装类 Integer 的源码看,他也是static修饰的,也就是说他也是类方法,只能通过类 加 点 调用
int a = Integer.parseInt("1234");
  • 把字符串1234,转换为整型的1234
  • 如果是字符串12.34的话,就调用double的包装类Double 来调用里面的parseDouble
    double a = Double.parseDouble("12.34")

2.5.2、大小写转换

2.5.2.1、大转小 toUpperCase()
  • 作用是把大写字符,转为小写字符
  • 所以他返回的还是一个新对象(字符串)
  • 是String类中的普通成员方法,所以依赖对象调用
String str1 = "abcdefg";
String str2 = str1.toUpperCase();
  • 此时把str1 的 abcdefg 转为大写的 ABCDEFG 存到 str2 中
  • 需要注意,此时虽然变为大写但是并没有改变 str1 中的字符串,而是重新创建了一个对象。上面说过,String中的value数组 是 private final修饰的,所以不能改变字符串
2.5.2.2、小转大 toLowerCase
  • 作用是把小写字符,转为大写字符
    • 所以他返回的还是一个新对象(字符串)
  • 看String源码,也是发现这个方法是String中的普通方法,所以依赖对象去调用
 String str1 = "ABCDEFG";String str2 = str1.toLowerCase();
  • 此时把str1 的 ABCDEFG 转为大写的 abcdefg 存到 str2 中
  • 需要注意,此时虽然变为小写但是并没有改变 str1 中的字符串,而是重新创建了一个对象。上面说过,String中的value数组 是 private final修饰的,所以不能改变字符串

2.5.3、字符串和数组之间的转换

2.5.3.1、字符串转数组 toCharArray()
  • 作用是把字符串,转变为数组
  • 所以他返回的是一个数组
  • 也是String中的普通成员方法,所以需要依赖对象才能调用
String str1 = "abcdefg";
char[] ch = str1.toCharArray();
  • 此时 把 abcdefg 转化为数组存到 字符数组 ch 中
  • 需要注意,此时虽然变为小写但是并没有改变 str1 中的字符串,而是重新创建了一个对象。上面说过,String中的value数组 是 private final修饰的,所以不能改变字符串
2.5.3.2、数组转字符串
  • 作用是把数组转变为字符串
  • 这里调用String 的构造方法就行,把数组作为参数传进去
char[] ch = new char{ a,b,c,d,e,f,g};
String str1 = new String(ch)

2.5.4、格式化 format

  • 是被static修饰的方法,所以是类方法,需要使用String 加点调用

2.6、字符串代替

2.6.1、 replace (char oldchar ,char newchar)
  • 作用就是 用新的字符替换旧的字符 ,并且是全部旧的字符都要换
  • 他返回的是一个新对象(字符串)
  • 他是String类中的普通方法,所以依赖对象去调用
String str1 = "abcdeafag";
String str2 = str1.replace('a','z');
  • 把str1中的所有 字符a 都变为 字符 z
  • 所以此时str2中存的是 zbcdezfzg
  • 需要注意,此时虽然把 a 替换成了 z 但是并没有改变 str1 中的字符串,而是重新创建了一个对象。上面说过,String中的value数组 是 private final修饰的,所以不能改变字符串
2.6.2、 replace (CharSequence target ,CharSequence replacement)
  • String 类中实现了CharSequence接口,换句话说,这里String 类型 的字符串,也能作为参数传进去(向上转型)
  • 作用是:用新的字符串代替旧的字符串,这里也是全部旧的字符串都要换
  • 他返回的是一个新对象(字符串)
  • 他是String类中的普通方法,所以依赖对象去调用
String str1 = "abcaeabcfgabc";
String str2 = str1.replace("abc", "de");
  • 把 str1 中 的所有 abc字符串 都换为 de字符串
  • 此时str2存的是deaedefgde
  • 需要注意,此时虽然把 abc 替换成了 de 但是并没有改变 str1 中的字符串,而是重新创建了一个对象。上面说过,String中的value数组 是 private final修饰的,所以不能改变字符串
2.6.3、 replaceAll (String regex ,String replacement)
  • 作用是:用新的字符串代替所有的旧字符串。和上一个方法一样
  • 他返回的也是一个新对象(字符串)
  • 他是String类中的普通方法,所以依赖对象去调用
String str1 = "abcaeabcfgabc";
String str2 = str1.replaceAll("abc", "de");
  • 把 str1 中 的所有 abc字符串 都换为 de字符串
  • 此时str2存的是deaedefgde
  • 需要注意,此时虽然把 abc 替换成了 de 但是并没有改变 str1 中的字符串,而是重新创建了一个对象。上面说过,String中的value数组 是 private final修饰的,所以不能改变字符串
2.6.4、 replaceFirst (String regex ,String replacement)
  • 作用是:用新的字符串代替第一个旧字符串。
  • 他返回的也是一个新对象(字符串)
  • 他是String类中的普通方法,所以依赖对象去调用
String str1 = "abcaeabcfgabc";
String str2 = str1.replaceFirst("abc", "de");
  • 把 str1 中 的第一个 abc字符串 都换为 de字符串
  • 此时str2存的是deaeabcfgabc
  • 需要注意,此时虽然把 abc 替换成了 de 但是并没有改变 str1 中的字符串,而是重新创建了一个对象。上面说过,String中的value数组 是 private final修饰的,所以不能改变字符串

2.7、字符串拆分

2.7.1、split(String regex)
  • 作用就是:字符串 按照regex 这个要求进行拆分,在字符串中只要有regex的字符,都要拆开
  • 他的返回类型是一个字符串数组,用来存拆分开来的字符串
  • 他是String类中的普通方法,所以需要依赖对象
  String str1 = "abc-def-ghi-jklmn";String[] strings = str1.split("-");
  • 把str1 字符串中 含有 - 字符的位置全部都要拆开
  • 在strings 的字符串数组中,存储的是 字符串abc ,字符串def,字符串ghi,字符串jklmn
  • 需要注意,此时虽然把 str1拆分开了, 但是并没有改变 str1 中的字符串,而是重新创建了一个对象。上面说过,String中的value数组 是 private final修饰的,所以不能改变字符串
2.7.2、split(String regex ,int limit)
  • 作用就是:字符串 按照regex 这个要求进行拆分,limit是拆分成多少份的意思,比如说我传个2进去,他只拆分一次,并且按照从头到尾的顺序拆
  • 他的返回类型也是 字符串数组
  • 他是String中的普通方法,所以也是需要依赖对象才能调用的
 String str1 = "abc-def-ghi-jklmn";String[] strings = str1.split("-",2);
  • 把str1 字符串中 含有 - 字符的位置,拆开1次
  • 在strings 的字符串数组中,存储的是 字符串abc ,字符串def-ghi-jklmn。注意:是按照顺序拆分,不是平均拆分
  • 需要注意,此时虽然把 str1拆分开了, 但是并没有改变 str1 中的字符串,而是重新创建了一个对象。上面说过,String中的value数组 是 private final修饰的,所以不能改变字符串
2.7.3、注意
  • 当以一些特殊的字符进行拆分时,需要给这些特殊的字符转义 如 “ | ” , “ * ” , “ + ”
  • 如何转义呢?在前面加上\,如 “ \\ | ” ,“ \\ * ”,“ \\ + ”
  • 那么更特殊的字符呢,比如以 " \ "作为拆分规则,那么此时是 两个 \ ,表示 一个 \ 即用 “ \\ ”表示“ \ ”
  • 除了这些还有一个需要注意的,就是当有多个拆分规则时,使用 “ | ”,进行隔开,或者用for循环拆两次
//多次拆分 
//方法一: 用“|”String str1 = "ab-cd-ef=gh=ij-kl=mn";String[] strings = str1.split("- | =")//方法二:使用循环String[] strings = str1.split("-");for (int i = 0 ; i < strings.length;i++){String[] tmp = strings[i].split("=");for(String str : tmp){System.out.println(str);}}

2.8、字符串截取

2.8.1 substring(int beginIndex)
  • 作用是:从字符串中截取部分内容
  • 传参传的是下标,表示从该下标截取到末尾
  • 所以返回值也是一个字符串
  • 他是String类中的普通类,所以是依赖对象才能调用的
String str1 = "helloworld";
String str2 = str1.substring(5);
  • 把str1 中下标为5到最后的这部分内容存到 str2中
  • 所以str2 中存的是world
  • 需要注意,此时虽然把 str1拆分开了, 但是并没有改变 str1 中的字符串,而是重新创建了一个对象。上面说过,String中的value数组 是 private final修饰的,所以不能改变字符串
2.8.2、substring(int beginIndex,int endIndex)
  • 参数的意思是,区间截取,就是beginIndex 下标 到 endIndex 下标 这部分内容截取出来
  • 其他和上面的一个参数的substring一样
 String str1 = "helloworld";String str2 = str1.substring(4,7);
  • 因为传参传的是 4,7 ,所以截取的是str1中的下标4 到下标7 之间的字符。注意区域是左闭右开的,即截取包含4下标,不包含7下标。
  • 所以str2 中存储的是 owo字符串

2.9、去除左右两边的空格 trim() 方法

  • 作用是去除左右两边的空格,保留中间的空格
  • trim 是String中的普通方法,所以依赖对象
  • 返回类似是String 类型,所以返回的是对象
String str1 = "    hello  world    "
String str2 = str1.trim();

此时str2 是 “hello world”,两边的空格没了

2.10、intern方法

三、字符串的不可变性

  • 我们知道,String中的 value 数组,是被private final 修饰的 ,所以一旦定义了字符串,就不能再修改。
  • 所以字符串中的内容是不可改变的。
  • 换句话说,所有涉及到修改字符串内容的操作都是创建一个新对象,修改的是新对象

四、字符串修改

  • 上面刚刚说了字符串不能修改,那么这里怎么又讲字符串修改呢?
  • 这里的修改就是说我们表面看到的情况,而不是修改深层的字符串内容。比如说 字符串的拼接,我们表面看到了字符串的修改,实际深层的代码并没有修改,我们看到的是新的对象
String str1 = "hello";
str1 = str1 + "world"
  • 我们看到的是修改了字符串,实际上 str1 + “ world ”,这个过程创建了一个新的对象,然后再把str1 这个引用指向新的对象
  • 那么问题来了,那么如果我们使用很多次拼接,比如我说个数10000次,那么创建对象,再销毁对象,再创建对象……,这个下去,效率岂不是很慢?换句话说,如果我不是拼接,而是调用其他的方法修改字符串。创建对象,销毁对象,始终效率很慢
  • 那么有什么解决方法呢?又给出了下面几个类

4.1、StringBuilder

  • 这个类里面有很多方法,详细去看源码了解
  • 在这里详解讲一个方法,append(String str),相当于String 的拼接
StringBuilder stringBuilder = new StringBuilder"hello";stringBuilder.append("world");

就这样就在hello的后面拼上了world

  • 既然说他解决了String 创建对象,销毁对象的问题,那么他是怎么实现的呢?他依然没有在原本的字符串上修改,而是创建一个新对象,所有的拼接都是在这个新对象里面完成的。也就是说如果拼接10000次,那么这10000次都在这个新创建的对象里面完成。所以说速率变得很快了。

4.1.1、什么情况下使用StringBuilder

  • 从上面看出String 和 StringBuilder 的最大区别是,String 的内容不能修改,而StringBuilder 创建的新对象是可以修改。所以说如果频繁修改字符串的情况下考虑使用StringBuilder。

4.1.2、StringBuilder 和 String 之间的互换

  • 因为这两个是不一样的类型,所以不能直接转换
4.1.2.1、StringBuilder 转 String
  • 调用 toString方法
4.1.2.2、String 转 StringBuilder
  • 使用StringBuilder 的构造方法,或者使用append()方法,因为append的形参可以是String类型

4.2、StringBuffer

  • 和StringBuilder,在功能上基本相同
  • 不同的是StringBuffer中的成员方法的修饰词
  • 使用了synchronized修饰,这个修饰词是线程安全操作

4.3、二者的区别

  • StringBuffer 中存在线程安全的修饰符
  • 功能这一块基本相同

4.4、里面的方法有空自己了解

http://www.dtcms.com/a/327761.html

相关文章:

  • 亚马逊手工制品类目重构:分类逻辑革新下的卖家应对策略与增长机遇
  • 高性能web服务器Tomcat
  • 嵌入式Linux内存管理面试题大全(含详细解析)
  • 元宇宙虚拟金融服务全景解析:技术创新、场景重构与未来趋势
  • 数据结构:链表栈的操作实现( Implementation os Stack using List)
  • LDAP 登录配置参数填写指南
  • 文件io ,缓冲区
  • 【智慧城市】2025年湖北大学暑期实训优秀作品(3):基于WebGIS的南京市古遗迹旅游管理系统
  • 简单的双向循环链表实现与使用指南
  • 小黑课堂计算机一级Office题库安装包2.93_Win中文_计算机二级考试_安装教程
  • 使用shell脚本执行需要root权限操作,解决APK只有系统权限问题
  • mysql参数调优之 sync_binlog (二)
  • 计算机网络摘星题库800题笔记 第2章 物理层
  • 防御保护11
  • Flutter GridView的基本使用
  • 17、CryptoMamba论文笔记
  • 基于大数据的在线教育评估系统 Python+Django+Vue.js
  • scikit-learn/sklearn学习|岭回归python代码解读
  • CVPR 2025丨机器人如何做看懂世界
  • 全面解析远程桌面:功能实现、性能优化与安全防护全攻略
  • 第十篇:3D模型性能优化:从入门到实践
  • AWT与Swing深度对比:架构差异、迁移实战与性能优化
  • 自己动手造个球平衡机器人
  • 基于 gRPC 的接口设计、性能优化与生产实践
  • open Euler--单master部署集群k8s
  • 【能耗监控数据聚合处理策略应用】
  • IIS 多用户环境中判断服务器是否为开发用电脑,数据状态比较
  • GeoScene 空间大数据产品使用入门(2)数据资源
  • 英伟达被约谈?国产替代迎来新机遇
  • 中国网络安全处罚综合研究报告(2020-2025)