字符串处理类
String和StringBuilder
目录
字符串处理类
String类
String常用方法
案例:
length()
charAt()
substring() 求子串
indexOf()
lastIndexOf()
getByte()
== 和equals方法的区别
String 的不可变性
String 和StringBuilder的区别:
StringBuilder和StringBuffer区别:
总结
String类
这个String类,是大家最常见的Java类,在刚接触java,我们的第一个代码“Hello,Word!”就有它的身影,“Hello,Word!”就一个字符串。
String常用方法
字符串,在我们的生活应用是非常非常常见的,比如:
- 我们播放视频,看视频时,这个播放器kennel要求的限制🚫必须是.mp4 或者加蜜后的 .ev4 格式,系统要去判断该格式。
- 在某一个新的网站我们要去注册一个用户,邮箱📮需要去验证格式是否准确,就需要去校验邮箱的格式。
String对象创建的常用方式:
- String s1 ="Kilig"; 创建一个字符串对象kilig,名为s1
- String s2 =new String(); 创建一个空字符串对象,名为s2
- String s3 = new String("Kilig"); 创建一个空字符串对象kilig,名为s3
String的常用方法:
案例:
让我们在eclipse中,创建一个com.kilig.string 的包,然后在这个包下创建一个StringDemoOne的测试类。让我们一起看看怎么使用上面的方法吧!
让我们看看首先看看length() substring() charAt() 这几个方法的使用
length()
是查看字符串长度的方法:
为什么是10呢,因为我们的这串字符串里包括空格,空格也被作为字符串插入到代码中了。
charAt()
CharAt(int index)
可以看到Index的值和对应的字符串的序号是这样排列的。
那么在这儿我们想取出“程”这个字符么?
substring() 求子串
在前面的学习中我们可以看到,
所以我们找到“编”的对应的index值就ok
同理,如果单纯提出“编程”两个字符,我们就可以用第二种方法了,需要注意的是:endIndex的值是指下一个该字符的下一个字符,而不是对应的字符的Index。
现在在来看看indexOf() lastIndexOf() 这几个方法的使用
indexOf()
用来求字符或者子串在字符串中第一次出现的位置
问题1:查找字符“A”在字符串中第一次出现的位置
要注意,此处输入的是该需要查找的字符的值,而不是index值。确而且得出来的值,就是该字符串对应的index值。
问题2: 查找字符“编程”在字符串中第一次出现的位置
因为我们在这儿是查找一个子串,所以选择String
lastIndexOf()
用来求字符或子串在字符串中最后一次出现的位置
问题1:查找字符“A”在字符串中最后一次出现的位置
问题2: 查找字符“编程”在字符串中最后一次出现的位置
【补充】我们可以看到,我们上面只是使用了其中的4种,还有额外的方法没有使用,可以看到,
lastIndexOf(int ch, int fromIndex) 这个其实就是查找 给定位置进行查找
让我们看一看:
接下来,让我们看看 getByte() 方法的使用:
getByte()
该方法需要注意:字符串和字节数之间的相互转换!,例如,需要将数据传送的网络上,此时,网络上的数据是二进制字节型,因此我们需要将我们的数据转化为二进制进行传输,当接受到数据时,我们就需要将字节数据转化为字符串来使用。
问题描述:字符串和byte数组之间的转换
首先,我们需要去定一个字符串,然后用一个数组来接收它,并且通过for循环打印出来。
- 步骤1:将字符串转化为byte数组
- 步骤2: 将byte数组转化为字符串
步骤1:将字符串转化为byte数组
可以看到,打印输出了一堆数字,这个就是 二进制字节的数据,当前为支持UTF-8的编码格式,所以我们去网上找到UTF-8的编码表,就可以看到一一对应的关系。 【🥳🥳🥳点击进行查看UTF-8 编码查询】
那么其实,
每一个字符都有对应的一个字节,该字节就是ascall码的数值,那么当我们划分“空格”对应的数字32后,可以发现,每一个汉子是占用三个字节的,也就是说:
- -25 -68 -106 :编
- -25 -88 -117 :程
- -27 -97 -70 :基
- -25 -95 -128 :础
- -17 -68 -127 :!
因为每个字节是8位,最大值是不可以超过2^8-1=127,然儿,汉子转化为字节是超过127,是溢出了,所以以负数表示。
步骤2: 将byte数组转化为字符串
在此基础上,我们首先浏览下Java API 【💁🏼💁🏼:点击打开Java API网址】
可以看到,这里输出的字符串和我们一开始定义的字符串是一样的,前提是:转换前的字节形式和代需要转换后的字节编码是同样的编码格式才可以正确完成转换。
但是有的小伙伴就会提问题了,如果字节数不一致怎么办?
可以看到,在构造方法中,还有一个用Charset作为参数,这个是字符集eg:utf-8,gbk等等都是字符集
我们尝试做一下,看看是什么效果:
可以看到,英文部分是没问题的,但是中文成了火星文,是我们所不认识的乱码,这是因为,在进行字节数向字符串转化是,我们本来用的就是utf-8,但是在这儿,我们强制转为GBK形式,所以会错错
那么解决这个问题其实也很简单:
- 如果我们非要使用编码格式为GBK的格式,我们可以在定义字符串的时候就将它定义为“GBK”的格式,这样转换之后的字符格式就是我们所需要的“GBK”,然后再用这个字节格式去转换我们所需要的中文字符。🥳
- 或者还有一种办法就是在建工程的时候,就将此次工程的代码格式改为“GBK”或者“UTF-8”。
此时我们在Java API中观察会发现,在下面还有一种byte() 的方法,
== 和equals方法的区别
首先我们来定义三个字符串:
可以看到,当使用equals时,比较的事字符串的内容,而使用==时,比较的示字符串的地址。
那么为什么会出现那样的结果呢?
内存空间中的:
- 栈:用来存放类的引用。
- 常量池:用来存放字符串常量
- 堆:用来存放用 new 创建的字符串对象
当使用
String str1 = "Kilig";
String str2 = "Kilig";
String str3 = new String("Kilig");
String str4 = new String("Kilig");
- 在堆生成str1 时,会将引用str1放在栈中存放,然后它生成的常量“Kilig”则放在了常量池进行存放。同样当栈生成str2时,结果在常量池找到了相同的常量“Kilig”就直接引用了。所以,str1和str2的地址是相同的。
- 但是当用字符new 构造一个新的常量时,会在栈中生成str3的引用,然后在堆生成字符常量“Kilig”。所以在这儿str1,str2的地址和str3是都不相同的。
- 然而,如果此时在创建一个 String str4 = new String("Kilig"); 时,会在栈中生成新的str4,然后在堆中在new一个新的堆地址,并且存放常量字符“Kilig”,所以此时 str3和str4的地址也是不一样的。
String 的不可变性
String的对象一旦被创建,那么时不可以被修改的,是不可变的,修改的过程其实就是创建了新的对象,其所指向的内存空间时不变的。
当创建:String str1 = "Kilig"; 时
当执行到 str1 ="Hello, "+ str1; 时 ,之前的“Kilig”就没有任何引用指向它,是被废弃的。而新的s1则指向的是Hello,Kilig
在这儿我们来做一个调用的字串的测试:
可以发现,调用子串,s2的值时没有发生变化的,那么这个整个操作过程是怎样的呢?
当执行语句 String s2 = new String("Hello, Kilig!"); 时,我们是在堆中开辟了一个新的字符串,执行的是步骤1,然后当,执行s2.substring(0, 5);时,输出的时结果“Hello”,那是因为,它将这个值存储到了常量池中,执行步骤2,整个过程,其实s2的指向卫视时一直没没有发生变化的。只是一个赋值的过程。
String 和StringBuilder的区别:
String具有不可变性,而StringBuilder不具备这样的特性
当频繁操作字符串时,使用StringBuilder来进行操作 (这是因为,在使用String时,会产生很多中间变量以及,在常量池中很多的废弃的数据,而StringBuilder可以防止这一类数据的产生)
StringBuilder和StringBuffer区别:
这两个基本是类似的。StringBuffer是线程安全,StringBuilder则没有,所以StringBilder的性能更高一些。
这是因为在线程安全的模式下速度会比较慢一些,而且平时的字符串处理都是单线程,所以大部分是用不到StringBuffer
我们打开Java API文档看看Stringbuilder类可以供我们使用的方法:💁🏼💁🏼Java API文档
可以看到,在我们创建Stringbuilder时,就默认给我们开辟了一个空的可以容纳16个字符的空间
我们来尝试一下,看看是什么效果:
其实整个环节在内存中的过程是这样的:
首先执行 StringBuilder str = new StringBuilder("点外卖");时,会在堆中创建字符串 :“点外面”
然后当执行
str.append("!");
str.append("我想吃汉堡");时,会在创建好的这个空间改先加上“!”,然后在加上“我想吃汉堡”。
还有方法二:就是直接在这个输出语句中调用append方法,然后紧跟着再嗲用一次,把想说的内容加上就ok
那么如果我们这个时候想在StringBuilder中的原来的字符变为“点外面,我先吃麻辣烫!”该怎么办呢?
其实我们有两种办法:
方案一:使用delete方法删除原来的“我想吃汉堡”在插入“我想吃麻辣烫”
方案二:使用replace方法直接替换
总结
- 仅在单线程情况下,我们常用StringBuilder,因为它的性能更好一些。但是当处理问题处于多线程模式时,我们就将使用StringBuffer。
- 此外还介绍了 == 和equals()方法的区别
- String的不可变性,StringBuilder则不具备这个特性,所以常需要频繁操作时,我们使用StringBuilder