详解 字符串—— String、StringBuffer 与 StringBuilder
本来这篇博文的内容,本人打算在之后的代码中一点一点通过实例讲解的,但是,本人发现,其实这里的知识点还是蛮重要的。
并且,字符串类型,在任何的程序语言中都是被认真对待的,所以,今天专门写一篇博文来介绍一下这个知识点!
[toc]
首先,什么是字符串呢?
相信学习过C语言的同学能够知道:
字符串是由多个字符组成的一串数据(字符序列)
字符串可以看成是字符数组
没错,再Java中,也是这样的,但是,相比于C语言,Java这种高级语言,对于字符串是有封装好的类的,那就是我们这篇博文的主题——String类。
String类:
在本人之前的博文中,提到过String类,但是只讲了这个类的变量,是字符串类型,并且和所有类型的变量相加,都会将其强转为字符串类型。
那么,现在,本人来讲解String类的其他的 性质 和 常用方法:
现在,本人来展示下String类的常用API:
- String类的构造方法:
常见构造方法:
- public String():
空构造- public String(byte[] bytes):
把字节数组转成字符串- public String(byte[] bytes,int index,int length):
把字节数组的一部分转成字符串(index:表示的是从第几个索引开始, length表示的是长度)- public String(char[] value):
把字符数组转成字符串- public String(char[] value,int index,int count):
把字符数组的一部分转成字符串- public String(String original):
把字符串常量值转成字符串
- String类的判断功能:
- public boolean equals(Object obj):
比较字符串的内容是否相同,区分大小写- public boolean equalsIgnoreCase(String str):
比较字符串的内容是否相同,忽略大小写- public boolean contains(String str):
判断字符串中是否包含传递进来的字符串- public boolean startsWith(String str):
判断字符串是否以传递进来的字符串开头- public boolean endsWith(String str):
判断字符串是否以传递进来的字符串结尾- public boolean isEmpty():
- String类的获取功能:
- public int length():
获取字符串的长度。- public char charAt(int index):
获取指定索引位置的字符- public int indexOf(int ch):
返回指定字符在此字符串中第一次出现处的索引。- public int indexOf(String str):
返回指定字符串在此字符串中第一次出现处的索引。- public int indexOf(int ch,int fromIndex):
返回指定字符在此字符串中从指定位置后第一次出现处的索引。- public int indexOf(String str,int fromIndex):
返回指定字符串在此字符串中从指定位置后第一次出现处的索引。
可以顺带提一下lastIndexOf系列- public String substring(int start):
从指定位置开始截取字符串,默认到末尾。- public String substring(int start,int end):
从指定位置开始到指定位置结束截取字符串。
- String类的转换功能:
- public byte[] getBytes():
把字符串转换为字节数组。- public char[] toCharArray():
把字符串转换为字符数组。- public static String valueOf(char[] chs):
把字符数组转成字符串。- public static String valueOf(int i):
把int类型的数据转成字符串。
注意:String类的valueOf方法可以把任意类型的数据转成字符串。- public String toLowerCase():
把字符串转成小写。- public String toUpperCase():
把字符串转成大写。- public String concat(String str):
把字符串拼接
- String类的其他功能:
1.String的替换功能:
- public String replace(char old, char new)
将指定字符进行互换- public String replace(String old, String new)
将指定字符串进行互换2.String的去除字符串两空格:
- public String trim() 去除两端空格
3.String的按字典顺序比较两个字符串
>- public int compareTo(String str)
会对照ASCII 码表 从第一个字母进行减法运算 返回的就是这个减法的结果
如果前面几个字母一样会根据两个字符串的长度进行减法运算返回的就是这个减法的结果
如果连个字符串一摸一样 返回的就是0
- public int compareToIgnoreCase(String str)
跟上面一样 只是忽略大小写的比较
我们先来展示一段代码:
package com.mec.study;
public class AboutString {
public static void main(String[] args) {
//String的第一种生成方法:
String str1 = new String("第一种生成方法");
//String的第二种生成方法:
String str2 = "第二种生成方法";
//String的第三种生成方法:
String str3 = String.valueOf(123456);
//展示字符串长度:
System.out.println(str1.length());
//取字符串字串:
System.out.println(str2.substring(3, 5));
//其他类型变量的强转,字符串的拼接
System.out.println(str3 + 321);
String code = null;
for (int i = 0; i < 3; i++) {
code = String.valueOf(1000 + i).substring(1);
System.out.println(code);
}
}
}
上面的代码里,蕴含着非常丰富的技巧,
那么现在,本人对上面的最后一个循环中的操作做一下说明:
有的同学可能会想,为什么不将上图中的第22行代码写成如下形式呢:
code = String.valueOf(i)
给i加1000,又将最高位“去掉”,不如不对其进行这两步操作。
这样想的同学,很遗憾,你还是在质疑本人的能力,若是不对其进行那两步操作,那么,就不会有“每个数自动补足三位(自动补零)”现象。
不信,我们来试试:
可以清晰地看到,没有了自动补零的现象!
这样的操作,其实在我们之后的工作中很常用的,希望大家能够对其重视!
下面要讲到String类的字符串的特点了:
特点:
字符串一旦被创建就不能改变
因为字符串的值是在方法区的常量池中划分空间、分配地址值的
我们还是通过一段代码来验证这个结论:
package com.mec.study;
public class AboutString {
public static void main(String[] args) {
String str1 = "123abc123defg123wxyz";
System.out.println("原str1: " + str1);
System.out.println(str1.replace("123", "ABCD"));
System.out.println("现str1: " + str1);
}
}
下面我们来看看运行结果:
可以看到,我们修改的部分在原Sting类的字符串中并没有被体现,即str并没有被改变!
事实上,str.replace()的结果是一个“新字符串”,是String新的对象!
我们不断地去new一个新的对象,相当于不断地去malloc,这样下来,是很浪费时间的!
那么,该如何解决这两点问题呢?
下面本人隆重介绍两个类——StringBuffer类 和 StringBuilder类:
StringBuffer类 和 StringBuilder类:
StringBuffer类 和 StringBuilder类这两个类的API甚至完全一样,但是,为什么要设置两个类呢?
答曰:
StringBuffer类
- 线程安全性高,但是效率低;
StringBuilder类
- 线程安全性低,但是效率高。
那么,本人现在介绍下这两个类:
(由于这两个类的API几乎完全相同,所以,本人在这里通过展示StringBuffer类的API来代表两个类都有的API 的展示)
StringBuffer的构造方法:
- public StringBuffer():
无参构造方法- public StringBuffer(int capacity):
指定容量的字符串缓冲区对象- public StringBuffer(String str):
指定字符串内容的字符串缓冲区对象
StringBuffer的方法:
- public int capacity():
返回当前容量。 理论值- public int length():
返回长度(字符数)。 实际值
StringBuffer的添加功能:
- public StringBuffer append(String str):
可以把任意类型数据添加到字符串缓冲区里面,并返回字符串缓冲区本身- public StringBuffer insert(int offset,String str):
在指定位置把任意类型的数据插入到字符串缓冲区里面,并返回字符串缓冲区本身
StringBuffer的替换和反转功能:
- public StringBuffer replace(int start,int end,String str):
从start开始到end用str替换- public StringBuffer reverse():
StringBuffer的截取功能:
- public String substring(int start):
从指定位置截取到末尾- public String substring(int start,int end):
截取从指定位置开始到结束位置,包括开始位置,不包括结束位置注意事项:
返回值类型不再是StringBuffer本身
StringBuffer和String的相互转换:
String --> StringBuffer:
- 通过构造方法
- 通过append()方法
B:StringBuffer --> String:
- 使用substring方法
- 通过构造方法
- 通过toString()方法
而至于StringBuilder这个类,所有的API都和StringBuffer类的大致相同,本人在这里就不啰嗦了。
现在,本人来展示下,这两个类的字符串的基本使用方法:
package com.mec.study;
public class AboutStringBuffer {
public static void main(String[] args) {
StringBuffer str = new StringBuffer("abc");
str.append(123);
System.out.println(str);
}
}
最后,本人来介绍一个非常重要的方法——得到计算机当前机器时间的方法( currentTimeMillis() ):
那么,本人现在来验证下StringBuffer 究竟比 String 的速度快了多少 :
package com.mec.study;
public class AboutStringBuffer {
public static void main(String[] args) {
//String 类字符串的拼凑耗时测试
String str = "";
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
str += 1;
}
long endTime = System.currentTimeMillis();
System.out.println("String拼凑字符串耗时: " + (endTime - startTime) + "毫秒");
//StringBuffer 类字符串的拼凑耗时测试
StringBuffer strBuffer = new StringBuffer();
startTime = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
strBuffer.append(i);
}
endTime = System.currentTimeMillis();
System.out.println("String拼凑字符串耗时: " + (endTime - startTime) + "毫秒");
}
}
在以上的测试中,我们能够直观地了解到:
若是我们处理的字符串只是简单常量,或者字符串在整个程序运行过程中变化不大,我们就推荐用String类字符串;
而若是我们的程序要求字符串不断变化,那么StringBuffer类字符串 和 StringBuilder类字符串 好些。