字符串详解
2018年02月25日 23:15:11 zhuwei1035838807 阅读数:38
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhuwei1035838807/article/details/79335453
一.字符串入门
1.字符串创建对象的方式:
(1) String str = "hello"; (在C语言中是没有字符串类型String,只有字符类型char,从而也就没有字符串类型的变量。一直以来 对这个问题都不是很清楚:只是知道C语言里有<string.h>这个头文件,所以就想当然的认为C语言里有 string这个 类型,可是通过下面这种形式来声明(定义)string的变量 string aString; 后来编程时发现通不 过编译,又查资料才知道原来C语言里压根就没有string这个类型,所以字符串都是通过char数组来存储 的, 而<string.h>这个头文件里声明的函数原型也全是针对char数组的种种操作。直到C++中才出现了 string这个类(注意是类, 不是类型)。)
这种方式创建字符串str2(若str2为新创建的字符串变量)的时候,Jvm(是指Java虚拟机)首先会检查字符串常量池中是否存在该字符串的对象,如果已经存在(若str1是已经在字符串常量池中创建了的字符串),那么就不会在字符串常量池中再创建了,直接返回该字符串在字符串常量池中的内存地址;如果该字符串在字符串常量池中并不存在,那么就会在字符串常量池中先创建该字符串的对象,然后再返回常量池中的内存地址。所以str2=str1(地址相等,因为都是使用的是常量池某一内存的地址),这样同一个字符串"abc"有两个名字(这两个变量名是定义在栈去还是常量池区?:确认这两个变量str1str2在栈内存上),一个地址(常量池内存中的地址)
(2) new String("hello");
这种方式创建字符串对象的时候,Jvm首先会检查字符串常量池中是否存在“hello”的字符串,如果已经存在,则不会在字符串常量池中创建了,(直接返回该字符串在常量池中的内存地址??);如果还没有存在(即还没有创建),那么就会在字符串常量池中创建“hello”字符串对象,然后还会去堆内存中再创建一份字符串的对象,把字符串常量池中的"hello字符串内容拷贝到堆内存中的字符串对象中,然后返回堆内存中字符串对象的内存地址(堆内存地址)。这样刚刚创建的一个字符串"abc"就有两个名字,一个是常量区的,同时常量区也对应一个地址str3;一个是堆内存区的。因为堆内存区的是拷贝的,所以它会在堆区有一个地址str4,这两个地址不相同(str3不等于str4)。(这两个变量名是定义在栈去还是常量池区?:确认这两个变量str3 str4还是在栈内存上)
2.实例一
(1) 实例:
-
public class Demo1 {
-
public static void main(String[] args) {
-
String str1 = "hello";//第一种创建字符串对象的方式
-
String str2 = "hello";//第一种创建字符串对象的方式
-
String str3 = new String("hello");//第二种创建字符串对象的方式
-
String str4 = new String("hello");//第二种创建字符串对象的方式
-
System.out.println("str1==str2?"+(str1==str2)); // true
-
System.out.println("str2==str3?"+(str2==str3)); //false
-
System.out.println("str3==str4?"+(str3==str4)); // false
-
System.out.println("str3.equals(str4)?"+(str3.equals(str4))); //true
-
}
-
}
(2) 运行结果:
(3) 分析:
①首先会在栈内存中声明一个变量str1,然后用双引号引起创建字符串的对象,这时候Jvm就会检查字符串常量池中是否有hello,没有的话就会在字符串常量池中先创建这个对象,然后把这个对象的内存地址返回给str1,假设它的内存地址是0x97,这时候返回给str1的就是0x97,这时候str1是指向了内存地址为0x97所存储的字符串对象。
②然后又声明了一个变量str2,用双引号引起创建字符串的对象,这时候Jvm就会检查字符串常量池中是否有hello,发现字符串常量池中已经有了hello,那么就不会在字符串常量池中再创建了。直接把字符串常量池中hello的内存地址返回给这个变量就可以,也就是说str2记录的内存地址也是0x97.所以现在str1和str2指向的是同一个对象,所以运行结果为true。
③首先在栈内存中声明一个变量str3,当new String的时候,里面有一个双引号引起来的字符串,有双引号引起来的都会先到字符串常量池中先检查,Jvm在字符串常量池中检查的时候发现已经存在hello,就不会在字符串常量池中再创建了(如果没有这个字符串常量,那就在常量池中创建一个字符串对象,同时有一个地址与该对象相对应。),接着有个new关键字,凡是遇到new关键字,Jvm都会在堆内存中开辟一块新的内存空间(言外之意就是:new String的情况就是同时完成两个任务:一个是String:在栈区创建一个字符串对象(当然首先在常量池中创建字符串常量对象),一个是马上在堆区再创建一个字符串对象,此时堆内存也有一个与该对象对应的地址,堆内存上创建的字符串对象的内容是从常量池中拷贝过来的),这时候会在堆内存中创建一个堆内存的对象,接着会把字符串常量池中的hello的内容拷贝到堆内存创建的对象中去,接着会把堆内存的内存地址返回给str3,比如说它的内存地址是0x78,str3记录的则是0x78的内存地址,它指向的是堆内存中创建的对象的内存地址。
④在栈内存中声明一个变量str4,字符串常量池中有hello,那么就不会再创建,会到堆内存中创建一个字符串对象,把字符串常量池中的内容拷贝到堆内存中创建的对象中,比如说它的内存地址是0x76,这时候栈内存中str4记录的就是0x76内存地址所存储的对象。
(4) 疑问:str3和str4的内存地址并不一样,为什么运行结果返回的是true?
虽然equals方法默认情况下(注意是默认)比较的是两个对象的内存地址,而现在用到的是字符串的对象,那么我们就不允许字符串的类对equals方法进行重写吗?字符串也可以重写equals方法,重写后就可以不遵循默认的情况,因为看的是String中有没有重写equals方法,所以应该查看String的源代码,查看String的源代码后我们发现,重写后的equals方法比较的是两个字符串对应的字符是否一致。
3.为什么比较字符串的时候建议使用equals而不是==号?
因为==号比较的是内存地址,但是我们在现实开发中一般都是比较内容是否一致,所以就不建议使用==号,如果使用==号,str2和str3就会是false,使用equals,只要两个字符串的内容一致那么返回的结果都是一致的。
注意:"=="用于比较 引用数据类型数据的时候比较的是两个对象的内存地址,equals方法默认情况下比较的也是两个对象的内存地址。
4. new String("abc")创建了几个对象?
创建了两个对象,一个对象是位于字符串常量池中,一个对象是位于堆内存中。
5.实例二
(1) 实例:
-
public class Demo2 {
-
public static void main(String[] args) {
-
test(null);
-
}
-
public static void test(String str){
-
if(str.equals("中国"))
-
{
-
System.out.println("回答正确");
-
}else{
-
System.out.println("回答错误");
-
}
-
}
-
}
(2) 运行结果:
(3) 分析:
首先str.equals("中国")运行后就会报空指针异常,如何避免这种错误?
那么就需要使用"中国".equals(str),这也是最简便的一种方式,调换位置后,"中国"是个常量,也就是这个常量在调用equals方法,这样就变成了常量是这个方法的调用者,变量作为参数这样就可以避免永远都不会出现空指针异常。因为如果函数的调用者是一个变量,这个变量有可能指向一个空的对象;如果函数的调用者是一个常量,常量不可能为空,永远都不可能为空也就不会出现空指针异常。这是一个编程习惯,使用equals方法时,我们一般都会让常量作为这个方法的调用者,这样就可以避免空指针异常的出现。
(4) 修改后的实例:
-
public class Demo3 {
-
public static void main(String[] args) {
-
test(null);
-
}
-
public static void test(String str){
-
if("中国".equals("str"))
-
{
-
System.out.println("回答正确");
-
}else{
-
System.out.println("回答错误");
-
}
-
}
-
}
(5) 运行结果:
二.String类的构造方法
注意:使用字节数组或者字符数组都可以构建一个字符串对象。
1.String();
(1) 该方法用于创建一个空内容的字符串对象。
(2) 实例:
-
//String类的无参的构造方法。
-
public class Demo4 {
-
public static void main(String[] args) {
-
String str = new String();//调用String类的无参的构造方法,相当于String str = " ";
-
System.out.println("字符串的内容是:"+str);
-
}
-
}
(3) 运行结果:
2.String(byte[] bytes) ;
(1) 该方法用于使用一个字节数组构建一个字符串对象;
(2) 实例:
-
//String(byte[] bytes) 使用一个字节数组构建一个字符串对象
-
public class Demo5 {
-
public static void main(String[] args) {
-
byte[] buf = {97,98,99};//这些字节数组里存储的都是那些字符对应的码值
-
String str = new String(buf); //使用一个字节数组构建一个字符串对象
-
System.out.println("字符串的内容:"+str);
-
}
-
}
(3) 运行结果:
3.String(byte[] bytes, int offset, int length)
(1) 参数详解:
bytes:要解码的数组(解码就是把数字转换成数字代表的字符)
offset:指定从数组中那个索引值开始解码。也就是说从字节数组中的哪一位开始查找对应的字符。
length:要解码多少个元素。也就是要查找多少个字符。
(2) 实例:
-
public class Demo6 {
-
public static void main(String[] args) {
-
byte[] buf = {97,98,99};
-
String str = new String(buf,1,2);//使用一个字节数组构建一个字符串对象,指定开始解码的索引值和解码的个数
-
System.out.println("字符串的内容:"+str);
-
}
-
}
(3) 运行结果:
4.String(char[] value);
(1) 使用一个字符数组构建一个字符串。
(2) 实例:
-
//String(char[] value) 使用一个字符数组构建一个字符串。
-
public class Demo7 {
-
public static void main(String[] args) {
-
char[] arr = {'马','上','毕','业','了'};
-
String str = new String(arr); //使用字符数组构建一个字符串
-
System.out.println("字符串的内容:"+str);
-
}
-
}
(3) 运行结果:
5.String(char[] value, int offset, int count);
(1) 使用一个字符数组构建一个字符串, 指定开始的索引值,与使用字符个数。
(2) 实例:
-
public class Demo8 {
-
public static void main(String[] args) {
-
char[] arr = {'马','上','毕','业','了'};
-
String str = new String(arr,2,2);
-
System.out.println("字符串的内容:"+str);
-
}
-
}
(3) 运行结果:
6.String(int[] codePoints,int offset,int count);
(1) 实例:
-
public class Demo9 {
-
public static void main(String[] args) {
-
int[] buf = {65,66,67};
-
String str = new String(buf,0,3);
-
System.out.println("字符串的内容:"+str);
-
}
-
}
(2) 运行结果:
三.String类的普通常用方法
1.获取的方法
(1) 方法:
①int length():该方法用于获取字符串的长度。
②char charAt(int index):传入一个索引值,根据索引值获取特定位置的字符 (注意角标越界)。
③int indexOf(String str):查找子串第一次出现的索引值,如果子串没有出现在字符串中,那么则返回-1表示。
④int lastIndexOf(String str):查找子串最后一次出现的索引值 , 如果子串没有出现在字符串中,那么则返回-1表示。
(2) 实例:
-
public class Demo3 {
-
public static void main(String[] args) {
-
String str = "abc你好ab你好";
-
System.out.println("字符串的字符个数:" + str.length());
-
System.out.println("根据索引值获取对应的字符:"+ str.charAt(3));
-
System.out.println("查找子串第一次出现的索引值:" + str.indexOf("你好"));
-
System.out.println("查找子串最后一次出现的索引值:" + str.lastIndexOf("你好"));
-
}
-
}
(3) 运行结果:
2.判断的方法
(1) 方法:
①boolean endsWith(String str):判断是否以指定字符串结束。
②boolean isEmpty():判断长度是否为0,也就是判断字符串是否为空内容。
③boolean contains(CharSequences):判断是否包含指定序列,该方法可以应用于搜索。
④boolean equals(Object anObject):判断是否相等,判断两个字符串的内容是否一致。是区分大小写的。
⑤boolean equalsIgnoreCase(String anotherString) 忽略大小写是否相等,验证码都是忽略大小写的。
(2) 实例:
-
public class Demo11 {
-
public static void main(String[] args) {
-
String str = "Demo.java";
-
System.out.println("是否以指定 的字符串结束:"+ str.endsWith("java"));
-
System.out.println("是否以指定 的字符串结束:"+ str.endsWith("va"));
-
System.out.println("是否以指定 的字符串结束:"+ str.endsWith("ja"));
-
System.out.println("判断字符串是否为空内容:"+str.isEmpty());
-
System.out.println("判断字符串是否包含指定的内容:"+ str.contains("Demo"));
-
System.out.println("判断两个 字符串的内容是否一致:"+ "DEMO.JAVA".equals(str));
-
System.out.println("判断两个字符串的内容是否一致(忽略大小写比较):"+ "DEMO.JAVA".equalsIgnoreCase(str));
-
}
-
}
(3) 运行结果:
3.转换的方法
注意:字节数组与字符数组、字符串他们三者之间是可以互相转换的。
(1) 方法:
①char[] toCharArray() :将字符串转换为字符数组。
②byte[] getBytes():将字符串转换为字节数组。
(2) 实例:
-
import java.util.Arrays;
-
public class Demo12 {
-
public static void main(String[] args) {
-
String str = "Demo.java";
-
char[] buf = str.toCharArray(); //把字符串转换字符数组
-
System.out.println("字符数组:"+ Arrays.toString(buf));
-
byte[] buf2 = str.getBytes(); //把字符串转字节数组
-
System.out.println("字节数组:"+ Arrays.toString(buf2));
-
}
-
}
(3) 运行结果:
4.其他的方法
注意:CharSequence是一个接口,而String类是它的实现类。
(1) 方法:
①String replace(String oldChar, String newChar):替换。
②String[] split(String regex):切割。
③String substring(int beginIndex):指定开始的索引值截取子串。
④String substring(int beginIndex, int endIndex):指定开始与结束的索引值截取子串。
⑤String toUpperCase():转大写。
⑥String toLowerCase():转小写。
⑦String trim():去除字符串首尾的空格。
(2) 实例:
-
public class Demo5 {
-
public static void main(String[] args) {
-
String str = "我们不学习";
-
System.out.println("指定新内容替换旧 的内容:"+ str.replace("不", "要好好"));
-
str = "我们要-好-好-学-习";//切成5份
-
String[] arr = str.split("-"); //根据指定的字符进行切割 。
-
System.out.println("字符串数组的内容:"+ Arrays.toString(arr));
-
str = "马上要毕业了";
-
System.out.println("指定开始的索引值截取子串:"+ str.substring(2));
-
System.out.println("指定开始与结束的索引值截取子串:"+ str.substring(2,6)); //方法重载,包头不包尾 注意:截取的内容是包括开始的索引值,不包括结束的索引值, 截取的位置是结束的索引值-1.
-
//注意,凡是Java方法中出现开始和结束的索引值,都是遵循包头不包尾
-
str = "abC中国";
-
System.out.println("转大写:" + str.toUpperCase());
-
str = "AbdfSDD";
-
System.out.println("转小写:"+ str.toLowerCase());
-
str = " 我们要 努力学习 ";
-
System.out.println("去除字符串首尾的空格:"+ str.trim());
-
}
-
}
(3) 运行结果:
四.字符串实例:
1.实例一
(1) 需求:自己实现trim的方法。
(2) 分析:只要我们能确定开始StartIndex和结束endIndex这两个位置的索引值,那么这个题目我们就能做出来。最关键的是这两个索引值应该如何确定?把这两个变量定义成这个字符串开始与结束的位置,首先用startIndex确定是否是空字符,是的话就前进一步,结束的索引值也要判断是否是空字符。是的话就后退一步。
(3) 实例:
-
public class Demo1 {
-
public static void main(String[] args) {
-
String str =" 我们 快要毕业了 ";
-
System.out.println(myTrim(str));
-
}
-
public static String myTrim(String str){
-
//先转换成字符 数组
-
char[] arr = str.toCharArray();
-
//定义两个 变量记录开始与结束 的索引值
-
int startIndex = 0 ;
-
int endIndex = arr.length -1;
-
//确定开始 的索引值
-
while(true){
-
if(arr[startIndex]==' '){
-
startIndex++;
-
}else{
-
break;
-
}
-
}
-
//确定结束 的索引值:
-
while(true){
-
if(arr[endIndex]==' '){
-
endIndex--;
-
}else{
-
break;
-
}
-
}
-
//截取子串返回
-
return str.substring(startIndex,endIndex+1);
-
}
-
}
(4) 运行结果:
2.实例二
(1) 需求:
获取上传文件名 "D:\\20180225\\day01\\Demo1.java"。从字符串中获取文件名为Demo1.java。
(2) 分析:
可以用切割的方法,按照"\\"来进行切割,把它分割成好几部分,返回一个字符串的数组,只获取字符串数组的最后一个就可以了;也可以用截取的方法,只要能确定D的索引值就可以了。那么如何确定D的索引值?也就是最后"\\"的索引值+1就是D的索引值。
(3) 实例:
-
public class Demo2 {
-
public static void main(String[] args) {
-
String str = "D:\\20180225\\day01\\Demo1.java";
-
getFileName(str);
-
}
-
public static void getFileName(String path){
-
int index = path.lastIndexOf("\\");//转义
-
String fileName = path.substring(index+1);
-
System.out.println("文件名:"+ fileName);
-
}
-
}
(4) 运行结果:
3.实例三
(1) 需求:
将字符串对象中存储的字符反序。例如:新中国好 -----> 好国中新。
(2) 分析:
只需要把它转换成一个字符数组,转成字符数组后就可以定义两个索引值,一个是开始的索引值startIndex,另一个是结束的索引值endIndex,这两个交换后,startIndex向前++,endIndex向后--,再继续进行交换,(要定义两个变量记录要交换位置的索引值,只要startIndex<endIndex那么就进行交换),当这个字符数组被反转后,我们只需要再使用这个字符数组构建一个字符串即可。
(3) 实例:
-
public class Demo3 {
-
public static void main(String[] args) {
-
String str = "新中国好";
-
System.out.println("翻转后的字符串:"+ reverse(str));
-
}
-
public static String reverse(String str){
-
char[] arr = str.toCharArray();
-
for(int startIndex = 0 , endIndex=arr.length-1 ; startIndex<endIndex; startIndex++,endIndex--){
-
char temp = arr[startIndex];
-
arr[startIndex] = arr[endIndex];
-
arr[endIndex] = temp;
-
}
-
//使用字符数组构建一个字符串。
-
return new String(arr);
-
}
-
}
(4) 运行结果
4.实例四
(1) 需求:
求一个子串在整串中出现的次数 。
(2) 分析:
先定义一个变量记录出现的次数,count = 0;接着定义一个变量用于记录开始寻找的索引值的位置,int fromIndex = 0;首先从索引值为0的地方开始找,找到第一个Java后,count++,然后继续开始向后寻找,第一次找到Java的索引值是3,第二次是从java后的a开始继续往后找,而这个a的索引值是7,那么第二次的fromIndex应该怎么计算出来?首先确定第一次java的索引值为3,接着java的长度是4,所以第二次从a的索引值7开始找。
(3) 实例:
-
public class Demo4 {
-
public static void main(String[] args) {
-
String str = "abcjavaabcjavaphpjava"; //统计java在这个字符串中出现的次数
-
getCount(str, "java");
-
}
-
//统计子串出现 的次数
-
public static void getCount(String str,String target){
-
int count = 0 ; //用于记录出现的次数
-
int fromIndex = 0; // 记录从那个索引值开始寻找目标子串
-
while((fromIndex = str.indexOf(target, fromIndex))!=-1){
-
//如果indexof方法返回 的不是-1,那么就是已经找到了目标 元素。
-
//如果这个方法返回的是-1意味着再往后找就没有了,所以循环的结束条件是只要不等于-1就继续往后找。
-
//indexOf会返回一个索引值,找到之后会有一个返回值,比如返回3,那么就应该用fromIndex来记录它。
-
//因为下次开始寻找的位置是
-
count++;
-
fromIndex = fromIndex+target.length();
-
}
-
System.out.println("出现的次数:"+ count);
-
}
-
}
(4) 运行结果:
五.StringBuffer类
1.前言
(1) 字符串的特点:字符串是常量,它们的值在创建之后不能更改。
(2) 字符串的内容一旦发生了变化,那么马上会创建一个新的对象。
(3) 实例:
-
public class Demo1 {
-
public static void main(String[] args) {
-
String str1 = "hello";
-
String str2 = str1+" world";
-
System.out.println("str1与str2是同一个 对象吗?"+(str1==str2));
-
}
-
}
运行结果如下图所示:
2.StringBuffer类:
(1) 字符串的内容不适宜频繁修改,因为一旦修改马上就会创建一个新的对象。如果不断频繁修改,在内存中就会有很多的字符串对象存在。如果需要频繁修改字符串的内容,建议使用字符串缓冲类(StringBuffer)。
(2) StringBuffer 是字符串的缓冲区,其实就是一个存储字符的容器,用它对字符串进行增删查改会非常方便。
(3) 疑问:使用Stringbuffer无参的构造函数创建 一个对象时,默认的初始容量是多少?如果长度不够使用了,自动增长多少倍?
通过查看源代码我们发现,StringBuffer 底层是依赖了一个字符数组才能存储字符数据的,该字符串数组默认 的初始容量是16, 如果字符数组的长度不够使用时,自动增长1倍,也就是是原来的2倍。
(4) 实例:
-
public class Demo2 {
-
public static void main(String[] args) {
-
//先使用StringBuffer无参的构造函数创建一个字符串缓冲类。
-
StringBuffer sb = new StringBuffer();
-
sb.append("java");
-
sb.append("java");
-
sb.append("java");
-
sb.append("java");
-
sb.append("java");
-
System.out.println(sb);//其初始容量为16个字符,但是为什么可以输出20个字符。
-
}
-
}
运行结果如下图所示:
3.StringBuffer类具备的方法:
(1) 增加的方法:
①append(boolean b) :有很多重载的方法,可以添加任意类型的数据到容器中。
-
package stringbuffer;
-
public class append {
-
public static void main(String[] args) {
-
StringBuffer sb = new StringBuffer();
-
//添加的方法
-
sb.append("abc");
-
sb.append(true);//把true变成字符串输出
-
sb.append(3.14f);
-
System.out.println("字符串缓冲类的内容:"+sb);
-
}
-
}
运行结果如下图所示:
②insert(int offset, boolean b):指定插入的索引值,插入对应的内容。
-
public class insert {
-
public static void main(String[] args) {
-
StringBuffer sb = new StringBuffer();
-
//插入的方法
-
sb.append("abc");
-
sb.insert(2,"小明");//在b和c之间插入小明,因为b和c之间的索引值是2.
-
System.out.println("字符串缓冲类的内容:"+sb);
-
}
-
}
运行结果如下图所示:
(2) 删除的方法
①delete(int start, int end):根据指定的开始与结束的索引值删除对应的内容。
-
public class delete {
-
public static void main(String[] args) {
-
StringBuffer sb = new StringBuffer();
-
sb.append("abc");
-
sb.insert(2,"小明");
-
System.out.println("执行删除操作前:"+sb);
-
//删除的方法
-
sb.delete(2, 4);//删除小明,删除的时候也是包头不包尾的。
-
System.out.println("执行删除操作后:"+sb);
-
}
-
}
运行结果如下图所示:
②deleteCharAt(int index):根据指定 的索引值删除一个字符。
-
public class deleteCharAt {
-
public static void main(String[] args) {
-
StringBuffer sb = new StringBuffer();
-
sb.append("abc");
-
sb.insert(2,"小明");
-
System.out.println("执行删除操作前:"+sb);
-
//删除
-
sb.deleteCharAt(3);//删除"明"
-
System.out.println("执行删除操作后:"+sb);
-
}
-
}
运行结果如下图所示:
(3) 修改的方法
①replace(int start, int end, String str):根据指定 的开始与结束索引值替代成指定的内容。
-
public class replace {
-
public static void main(String[] args) {
-
StringBuffer sb = new StringBuffer();
-
sb.append("abc");
-
sb.insert(2,"小明");
-
System.out.println("执行替换操作前:"+sb);
-
//替换
-
sb.replace(2,4,"张三");//把小明替换成张三
-
System.out.println("执行替换操作后:"+sb);
-
}
-
}
运行结果如下图所示:
②reverse():反转字符串缓冲类的内容。abc--->cba
-
public class reverse {
-
public static void main(String[] args) {
-
StringBuffer sb = new StringBuffer();
-
sb.append("abc");
-
sb.insert(2,"小明");
-
System.out.println("执行反转操作前:"+sb);
-
//反转字符串的内容
-
sb.reverse();
-
System.out.println("执行反转操作后:"+sb);
-
}
-
}
运行结果如下图所示:
③setCharAt(int index, char ch):把指定索引值的字符替换成指定的字符。
-
public class setCharAt {
-
public static void main(String[] args) {
-
StringBuffer sb = new StringBuffer();
-
sb.append("abc");
-
sb.insert(2,"小明");
-
System.out.println("执行替换操作前:"+sb);
-
//替换单个字符
-
sb.setCharAt(3, '红');//把'明'替换成'红'
-
System.out.println("执行替换操作后:"+sb);
-
}
-
}
运行结果如下图所示:
④substring(int start, int end):根据指定的索引值截取子串。
-
public class substring {
-
public static void main(String[] args) {
-
StringBuffer sb = new StringBuffer();
-
sb.append("abc");
-
sb.insert(2,"小明");
-
//截取小明
-
String subString = sb.substring(2, 4);//返回类型是String类型
-
System.out.println("子串的内容:"+subString);
-
}
-
}
运行结果如下图所示:
⑤ensureCapacity(int minimumCapacity):指定StringBuffer内部的字符数组长度的。基本很少用到。
如果想指定字符数组的初始容量可以使用带参的构造方法来指定。
-
public class ensureCapacity {
-
public static void main(String[] args) {
-
StringBuffer sb = new StringBuffer();
-
sb.append("abc");
-
sb.insert(2,"小明");
-
sb.ensureCapacity(20);//指定字符数组的长度为20,默认是16
-
}
-
}
(4) 查看的方法
①indexOf(String str, int fromIndex):查找指定的字符串第一次出现的索引值,并且指定开始查找的位置。
-
public class indexOf {
-
public static void main(String[] args) {
-
StringBuffer sb = new StringBuffer();
-
sb.append("abcjavaabc");
-
int index = sb.indexOf("java", 0);//从索引值为0的位置开始找
-
System.out.println("返回的索引值为:"+index);
-
}
-
}
运行结果如下图所示:
②capacity():查看当前字符数组的长度。
-
public class capacity {
-
public static void main(String[] args) {
-
StringBuffer sb = new StringBuffer();
-
sb.append("abcjavaabc");
-
//查看当前字符数组的长度
-
System.out.println("当前字符数组的长度是:"+sb.capacity());//16
-
sb.append("javajava");//此时存储了18个字符,那么这时候当前字符数组的长度又是多少?
-
System.out.println("当前字符数组的长度是:"+sb.capacity());//34,因为字符串的长度会增长一倍+2
-
}
-
}
运行结果如下图所示:
③length():查看存储字符的个数。
-
public class length {
-
public static void main(String[] args) {
-
StringBuffer sb = new StringBuffer();
-
sb.append("abcjavaabc");
-
sb.append("javajava");
-
System.out.println("查看当前字符数组存储字符的个数:"+sb.length());
-
}
-
}
运行结果如下图所示:
④charAt(int index):根据指定的索引值查找字符
-
public class charAt {
-
public static void main(String[] args) {
-
StringBuffer sb = new StringBuffer();
-
sb.append("abcjavaabc");
-
sb.append("javajava");
-
System.out.println("根据指定的索引值查找字符:"+sb.charAt(2));
-
}
-
}
运行结果如下图所示:
⑤toString():把字符串缓冲类的内容转成字符串返回。
现在stringBuffer里存储了很多的字符数据,假设有一个test方法,这个方法是要接收一个字符串的,而字符的内容是存储在StringBuffer里的。而现在调用这个test方法应该如何调用呢?首先肯定不能把sb传进去,因为类型不一样,如何把这个容器中存储的字符转换成字符串呢?可以用sb.toString()方法,这样就会把里面存储的内容,以字符串的形式返回。
-
public class toString {
-
public static void main(String[] args) {
-
StringBuffer sb = new StringBuffer();
-
sb.append("abcjavaabc");
-
sb.append("javajava");
-
String content = sb.toString();
-
test(content);
-
}
-
public static void test(String str){
-
System.out.println("字符串缓冲类的内容是:"+str);
-
}
-
}
运行结果如下图所示:
六.StringBuilder类
1.StringBuffer 与 StringBuilder的相同处与不同处:
(1) 相同点:
①两个类都是字符串缓冲类。
②两个类的方法都是一致的。(只要是StringBuffer有的方法,StringBuilder一样有)
(2) 不同点:
①StringBuffer是线程安全的,操作效率低 ,StringBuilder是线程非安全的,操作效率高。
(所谓的安全是指在一个时间段里只会允许一个线程来操作这份代码,而线程不安全是指在一个时间段里一份代码可以由多个线程来执行)
②StringBuffer是jdk1.0出现 的,StringBuilder 是jdk1.5的时候出现的。
2.推荐使用:StringBuilder,因为操作效率高。