当前位置: 首页 > 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.lryc.cn/news/618873.html

相关文章:

  • Python 多进程及进程间通信
  • C++实现LINGO模型处理程序
  • 杰里常用功能API
  • Navicat更改MySql表名后IDEA项目启动会找原来的表
  • 腾讯codebuddy.ai 安装实测【从零开始开发在线五子棋游戏:完整开发记录】
  • 服务降级方式
  • 2025年最新原创多目标算法:多目标酶作用优化算法(MOEAO)求解MaF1-MaF15及工程应用---盘式制动器设计,提供完整MATLAB代码
  • 拖动式看板工具TOP6:2025最新评测
  • 疯狂星期四文案网第37天运营日记
  • 看懂 Makefile 第一课:基础
  • 企业培训笔记:宠物信息管理--实现宠物信息的添加
  • c#,vb.net全局多线程锁,可以在任意模块或类中使用,但尽量用多个锁提高效率
  • 行业分享丨SimSolid 在汽车零部件开发中应用的可行性调研及实践
  • 基于Hadoop的汽车价格预测分析及评论情感分析可视化系统
  • 海信IP108H(53U1M)_S905L-B主控-无线SV6051P/8822CS(通刷咪咕mg100_mg101)线刷固件包
  • grpc浅入门
  • 一键生成 Android 适配不同分辨率尺寸的图片
  • 什么是 Spring MVC?
  • AuthController类讲解
  • 龙舌兰人造植物、Apple Watch保护壳、厨房水槽收纳架、家居磁性挂钩等亚马逊热销单品,正在外观专利TRO维权!
  • 备战国赛算法讲解——马尔科夫链,2025国赛数学建模B题详细思路模型更新
  • VUE+SPRINGBOOT从0-1打造前后端-前后台系统-会议记录
  • Linux网络--2.2、TCP接口
  • 5 重复匹配
  • 51 单片机分层架构的模块依赖关系图
  • 详细解释RBFT和NoxBFT及RAFT的差异
  • PCIe Electrical Idle Sequences ( EIOS and EIEOS )
  • Java 22 新特性:字符串模板(String Templates)让拼接更优雅、更安全
  • 机械学习--TF-IDF实战--红楼梦数据处理
  • 什么是iOS超级签名?为何它能解决企业签名的“掉签”难题?