三者区别
StringBuilder和StringBuffer非常相似,均代表可变的字符序列,而且方法也一样。
- String:不可变字符序列
- StringBuffer:可变字符序列、效率低、线程安全
StringBuilder:可变字符序列、效率高、线程不安全
由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。
这里顺带讲讲String的使用陷阱:
String s = "a";
s = s + "b";
在相加的时候,实际上原来的 "a" 字符串对象已经丢弃了,现在又产生了一个字符串 s+"b" (也就是"ab")。
如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放在循环中,会极大影响程序的性能。
StringBuilder和StringBuffer的常用方法
注意:不能直接用扫描器输入StringBuilder和StringBuffer,需要构造函数。
只能StringBuilder sb = new StringBuilder(in.next());
,
而不能像String一样,String str = in.next();
。
StringBuilder和StringBuffer的方法一样,以下列出了StringBuffer的常用方法:
方法 | 返回类型 | 描述 | 备注 |
---|---|---|---|
append(String str) | StringBuffer | 追加内容 | 此方法可以添加任何数据类型 |
insert(int offset, String str) | StringBuffer | 在指定位置处插入指定字符 | |
reverse() | StringBuffer | 将内容反转保存 | |
replace(int start, int end, String str) | StringBuffer | 指定内容替换 | |
delete(int start, int end) | StringBuffer | 删除指定范围的字符串 | |
substring(int start) | String | 字符串截取,指定开始点 | |
substring(int start, int end) | String | 截取指定范围的字符串 | |
indexOf(String str) | int | 查找指定字符串是否存在,返回索引号 | |
indexOf(String str, int fromIndex) | int | 从指定位置开始查找指定字符是否存在,返回索引号 | |
length() | int | 求出内容长度 | |
toString() | String | 将内容变为String类型 | 继承Object类的方法 |
String的常用方法
String类用来存储字符串。
例如:
String a = "Hello";
方法 | 返回类型 | 描述 | 备注 |
---|---|---|---|
toCharArray() | char[] | 将一个字符串变为字符数组 | 字符串→字符数组 |
charAt() | char | 将指定索引处的字符返回 | 字符 |
getBytes() | byte[] | 使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中 | |
length() | int | 返回此字符串的长度 | 长度 |
indexOf(String str) | int | 返回指定子字符串在此字符串中第一次出现处的索引(若没有,返回-1) | 可以用来查找此子字符串是否存在 |
indexOf(String str, int fromIndex) | int | 返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始 | |
trim() | String | 返回字符串的副本,忽略前导空白和尾部空白 | |
replace(char oldChar, char newChar) | String | 用 newChar 替换此字符串中出现的所有 oldChar | replace(" ","")可以用来去掉所有空格 |
substring(int beginIndex) | String | 对字符串进行截取,从begin开始,到结尾结束 | |
substring(int begin, int end) | String | 对字符串区间[begin, end)进行截取 | 子字符串 |
equals(String str) | boolean | 判断两个字符串是否相等 | |
equalsIgnoreCase(String str) | boolean | 不区分大小写比较两个字符串是否相等 | |
toUpperCase() | String | 将一个字符串全部变成大写字母 | |
toLowerCase() | String | 将一个字符串全部变为小写字母 | |
startsWith(String prefix) | boolean | 判断是否以指定字符串开头 | |
endsWith(String suffix) | boolean | 判断是否以指定字符串结尾 | |
split(String regex) | String[] | 按指定的正则表达式、分隔字符或字符串对内容进行分割,并将分割后的结果作为字符串数组返回 | 分割字符串 |
matches(String regex) | boolean | 告知此字符串是否匹配给定的正则表达式 | |
replaceAll(String regex, String replacement) | String | 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串 |
字符串连接
可以直接用+号,如
String a = "Hello";
String b = "world";
System.out.println(a + ", " + b + "!"); // output "Hello, world!"
字符串查找
String提供了两种查找字符串的方法,即 indexOf()
与 lastIndexOf()
方法。
indexOf(String s)
:用于返回参数字符串 s 在指定字符串中首次出现的索引位置
当调用字符串的indexOf()方法时,会从当前字符串的开始位置搜索 s 的位置。- 如果没有检索到字符串 s,该方法返回-1
String str ="We are students"; int size = str.indexOf("a"); // 变量 size 的值是 3
lastIndexOf(String str)
:用于返回字符串最后一次出现的索引位置。
当调用字符串的lastIndexOf()
方法时,会从当前字符串的开始位置检索参数字符串 str,并将最后一次出现 str 的索引位置返回。- 如果没有检索到字符串 str,该方法返回-1。
- 如果
lastIndexOf()
方法中的参数是空字符串"",则返回的结果与 length 方法的返回结果相同。
获取指定索引位置的字符
使用charAt()
方法可将指定索引处的字符返回。
String str = "Hello world";
char mychar = str.charAt(5); // mychar 的结果是 w
获取子字符串
通过String类的substring()
方法可对字符串进行截取。
这些方法的共同点就是都利用字符串的下标进行截取,且应明确字符串下标是从 0 开始的。在字符串中空格占用一个索引位置。
substring(int beginIndex)
:从begin开始,到结尾结束String str = "Hello world"; String substr = str.substring(3); //获取字符串,此时 substr 值为 lo world
substring(int beginIndex, int endIndex)
:begin和end区间是前闭后开的,[begin, end)注意:其实这个区间前闭后开是针对字符来说的,看下面举的例子,0~3截取了Hel这三个字符,即 [0, 3),第0、1、2个字符。
- beginIndex:开始截取子字符串的索引位置
- endIndex:子字符串在整个字符串中的结束位置
理解:但是,我们可以从存储机制去理解它。
Hello World 在系统里是这样存储的:
我们截取了地址0~3,所以截取了Hel这三个字符。String str = "Hello world"; String substr = str.substring(0,3); //substr 的值为 Hel
去除空格
trim()
方法返回字符串的副本,清除了左右两端的空格。
String str = " hello ";
System.out.println(str.trim());
//程序运行结果:hello
字符串替换
replace(String oldChar,String newChar)
方法可实现将指定的字符或字符串替换成新的字符或字符串。
- oldChar:要替换的字符或字符串
- newChar:用于替换原来字符串的内容
注意:如果要替换的字符 oldChar 在字符串中重复出现多次,replace()方法会将所有 oldChar 全部替换成 newChar。需要注意的是,要替换的字符 oldChar 的大小写要与原字符串中字符的大小写保持一致。
String str= "address";
String newstr = str.replace("a", "A");// newstr 的值为 Address
判断字符串是否相等(切不可使用==)
equals(String otherstr)
:
如果两个字符串具有相同的字符和长度,则使用equals()
方法比较时,返回 true。注意:equals()方法比较时,区分大小写。
equalsIgnoreCase(String otherstr)
:注意:
equalsIgnoreCase()
方法与equals()
类似,不过在比较时忽略了大小写。
equals()与==的区别:
- ==:
- 如果作用于基本数据类型的变量(如 byte,short,char,int,long,float,double,boolean),则直接比较其存储的“值”是否相等;
- 如果作用于引用类型的变量(如 String类),则比较的是所指向的对象的地址(即 是否指向同一个对象)。
- equals()方法:是基类Object中的方法,因此对于所有的继承于Object的类都会有该方法。在Object类中,equals()方法是用来比较两个对象的引用是否相等,即 是否指向同一个对象。
是不是感觉equals()在Object类中跟==好像是一样的描述啊??没错,就是一样的,不是我写错了!
Java中Object类是所有类的父类,它里面定义了equals()方法:
public boolean equals(Object obj) {
return (this == obj);
}
若object1.equals(object2)为true,则表示equals1和equals2实际上是引用同一个对象。
注意:对于equals()方法,equals()方法不能作用于基本数据类型的变量。
- 如果没有对equals()方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
- 而String类对equals方法进行了重写,用来比较指向的字符串对象所存储的字符串内容是否相等。
其他的一些自带的引用数据类型,如 Double,Date,Integer等,都对equals()方法进行了重写,用来比较指向的对象所存储的内容是否相等。
按字典顺序比较两个字符串
compareTo()
方法为按字典顺序比较两个字符串,该比较基于字符串中各个字符的 Unicode 值,按字典顺序将此 String 对象表示的字符序列与参数字符串所表示的字符序列进行比较。
- 如果按字典顺序此 String 对象位于参数字符串之前,则比较结果为一个负整数;
- 如果按字典顺序此 String 对象位于参数字符串之后,则比较结果为一个正整数;
- 如果这两个字符串相等,则结果为0.
字母大小写转换
- 字符串的
toLowerCase()
方法可将字符串中的所有字符从大写字母改写为小写字母, - 而
toLowerCaseUpperCase()
方法可将字符串中的小写字母改写为大写字母。
str.toLowerCase();
str.toUpperCase();
字符串分割
使用split()
方法可以使字符串按指定的分隔字符或字符串对内容进行分割,并将分割后的结果作为字符串数组返回。
str.split(String regex);
:regex为分割字符串的分割符,也可以使用正则表达式。
注意:没有统一的对字符串进行分割的符号,如果想定义多个分割符,可使用符号“|”。(这个是正则表达式的“或”概念)
例如,“,|=”表示分割符分别为“,”和“=”。
String str = "hello world";
String[] s = str.split(" ");
for(int i=0; i<s.length; i++) {
System.out.println(s[i]);
}
程序运行结果:
hello
world
总结
总结:
- 如果要操作少量的数据用 String;
- 多线程操作字符串缓冲区下操作大量数据 StringBuffer;
- 单线程操作字符串缓冲区下操作大量数据 StringBuilder。
字符串 | 字符序列 | 效率 | 线程 | 线程安全 | 备注 |
---|---|---|---|---|---|
String | 不可变 | 低 | String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量优先的内存空间 | ||
StringBuffer | 可变 | 中 | 多线程操作字符串 | 线程安全 | StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量 |
StringBuilder | 可变 | 高 | 单线程操作字符串 | 线程不安全 | 可变类,速度更快 |