String类是Java内置的用来表示字符串的类,所有的字面量字符串,都是String类的实例实现。当然,我们也可以通过new一个新对象的方式,创建一个String实例。
java
public class App {
public static void main(String[] args) {
// 方式1:使用字面量
String s1 = "hello";
// 方式2:new
String s2 = new String("hi");
}
}
需要注意的是,使用字面量创建的字符串,字符串会存储到内存的字符串常量池中。在Java有所谓"享元模式"(共享元素),即两个变量如果引用相同的字符串内容,系统会指向同一个字符串常量池中内的字符串。证明如下:
java
public class Demo0 {
public static void main(String[] args) {
// 用字面量创建一个String对象
String s1 = "hello";
// 用字面量创建另外一个String对象,字符串内容完全相同
String s2 = "hello";
// 证明两个变量都是同一个对象的引用
System.out.println(s1 == s2); // true
}
}
而如果不是用的字面量,是用new创建两个String对象,则是完全不同的结果。用new创建两个字符串内容完全相同的String对象,会在内存堆里存储对象。两个变量则是完全不同的对象。证明如下:
java
public class Demo1 {
public static void main(String[] args) {
// 用new创建一个String对象
String s1 = new String("hello");
// 用new创建另外一个String对象,字符串内容完全相同
String s2 = new String("hello");
// 证明两个变量是两个对象
System.out.println(s1 == s2); // false
}
}
字符串在编程中,是最常见的几种对象,因此String方法非常非常丰富。String对象是不可变的,其方法产生的字符串,都是返回一个新的String对象。
String常用的方法
String类的常见方法可以划分为基本操作、转换操作、替换与去除、截取与分隔、判断操作等分类。
String类的基本操作方法有:获取字符串长度、返回字符在字符串中第一次、最后一次出现的索引、返回字符串索引上的字符等。
java
public class Demo2 {
public static void main(String[] args) {
String s1 = "hello";
// 获取字符串的长度
System.out.println(s1.length()); // 5
// 返回字符在字符串中第一次出现的索引
System.out.println(s1.indexOf('l')); // 2 (索引从0开始)
// 返回字符在字符串中最后一次出现的索引
System.out.println(s1.lastIndexOf('l')); // 3
// 返回指定索引的字符
System.out.println(s1.charAt(1)); // e
}
}
String类的转换操作有:将字符串转换为字符数组、将int类型转换为字符串、将字符串中所有字符转换为小写、将字符串中所有字符转换为大写
java
public class Demo3 {
public static void main(String[] args) {
String s1 = "hello";
// 将字符串转换为字符数组
char[] chs = s1.toCharArray();
for (int i = 0; i < chs.length; i++) {
System.out.print(chs[i]); // hello
}
System.out.println();
// 将int类型转换为字符串
int a = 10086;
String s2 = String.valueOf(a);
System.out.println(s2); // 10086
// 将字符串中的字符全部转换为大写
String s3 = s1.toUpperCase();
System.out.println(s3); // HELLO
// 将字符串中的字符全部转换为小写
String s4 = s1.toLowerCase();
System.out.println(s4); // hello
}
}
String类的替换去除操作:用新字符串替换原有字符串,得到一个新的字符串;去除字符串首尾的空格。
java
public class Demo4 {
public static void main(String[] args) {
String s1 = "hello";
// 用新字符串替换原有字符串,得到一个新的字符串
String s2 = s1.replace("hello", "helloworld");
System.out.println(s2); // helloworld
// 去除字符串首尾的空格
String s3 = " hello ";
String s4 = s3.trim(); // 建议用strip()替代
System.out.println(s4); // hello
}
}
需要注意:
trim()只能去除ASCII码≤32 的空白字符(空格、制表符、换行等),但不能去除全角空格或其他Unicode空白字符。Java 11+引入了strip()方法来解决这个问题。因此,建议使用strip()方法替代trim()方法
String类的截取与分隔操作有:根据参数将原字符串分隔为若干个字符串(字符串数组)、截取从指定索引后的所有字符、截取从指定开始索引到指定结束索引之间的字符。
java
public class Demo5 {
public static void main(String[] args) {
String s1 = "this is a text";
// 将原字符串分隔为若干个字符串(字符串数组)
String[] arr = s1.split(" ");
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
// 截取从指定索引后的所有字符
String s2 = "helloworld";
System.out.println(s2.substring(5)); // world
// 截取从指定开始索引到指定结束索引之间的字符
System.out.println(s2.substring(2, 4)); // ll
}
}
String类的判断操作有:判断与指定字符串比较是否相等、判断字符串是否以指定字符串开始、判断字符串是否以指定字符串结尾、判断字符串是否包含指定的字符序列、判断字符串是否为空(字符串长度为0)。
java
public class Demo6 {
public static void main(String[] args) {
String s1 = "hello";
// 判断与指定字符串比较是否相等
System.out.println(s1.equals("hello")); // true
// 判断字符串是否以指定字符串开始
System.out.println(s1.startsWith("he")); // true
// 判断字符串是否以指定字符串结尾
System.out.println(s1.endsWith("lo")); // true
// 判断字符串是否包含指定的字符序列
System.out.println(s1.contains("llo")); // true
// 判断字符串是否为空
System.out.println(s1.isEmpty()); // false
}
}
StringBuilder和StringBuffer类
由于String对象是不可变对象,因此String类的所有方法若是返回字符串,都是返回一个新的字符串。由于字符串是高频出现的对象,而因为字符串的不可变特性,对内存的开销较大。
因此,Java系统前后推出了StringBuffer类和StringBuilder类,作为String类的补充。两者都是可变的字符串对象,两者的方法都几乎相同,都是在原字符串上进行变更修改,而不是产生一个新的字符串对象。
以StringBuilder为例,演示StringBuilder和StringBuffer类的常用方法。
java
public class Demo7 {
public static void main(String[] args) {
StringBuffer str = new StringBuffer("hello");
// append方法:添加字符串
str.append(" world");
System.out.println(str); // hello world
// insert方法:在指定位置添加字符串
str.insert(5, " java's");
System.out.println(str); // hello java's world
// replace方法:替换字符串
str.replace(5, 12, " java");
System.out.println(str); // hello java world
// delete方法:删除字符串
str.delete(5, 10);
System.out.println(str); // hello world
}
}
StringBuffer类和StringBuilder类区别在于相对运行快慢和线程安全性,StringBuffer是线程安全的,运行性能比StringBuilder慢。而StringBuilder虽然是线程不安全的,但是优势在于运行速度快。
java
package string.demo2;
public class Demo7 {
public static void main(String[] args) {
StringBuffer str0 = new StringBuffer("hello");
StringBuilder str1 = new StringBuilder("hello");
// 测试StringBuffer对象方法的运行时间
long start = System.nanoTime();
// append方法:添加字符串
str0.append(" world");
System.out.println(str0); // hello world
// insert方法:在指定位置添加字符串
str0.insert(5, " java's");
System.out.println(str0); // hello java's world
// replace方法:替换字符串
str0.replace(5, 12, " java");
System.out.println(str0); // hello java world
// delete方法:删除字符串
str0.delete(5, 10);
System.out.println(str0); // hello world
long end = System.nanoTime();
System.out.println("StringBuffer运行时间:" + (end - start) + "纳秒");
System.out.println("------------------------------------------------");
// 测试StringBuilder对象方法的运行时间
long start1 = System.nanoTime();
str1.append(" world");
System.out.println(str1);
str1.insert(5, " java's");
System.out.println(str1);
str1.replace(5, 12, " java");
System.out.println(str1);
str1.delete(5, 10);
System.out.println(str1);
long end1 = System.nanoTime();
System.out.println("StringBuilder运行时间:" + (end1 - start1) + "纳秒");
}
}
shell
hello world
hello java's world
hello java world
hello world
StringBuffer运行时间:398609纳秒
------------------------------------------------
hello world
hello java's world
hello java world
hello world
StringBuilder运行时间:92160纳秒
进程已结束,退出代码为 0
由此可见,StringBuilder确实要更快一些。一般情况下,我们都是单线程运行程序,因此推荐用StringBuilder。