字符串概述
Java没有内置的字符串类型,而是在标准Java类库中提供了一个预定义类 String。
每一个使用双引号引起来的字符串都是 String 类的一个实例。
子串
String 类的 substring 方法可以从一个较长的字符串提取出一个子串。
String str = "Hello";
String subStr = str.substring(0,3);
System.out.println(subStr); // Hel
substring 方法的第二个参数是不想复制的第一个位置。即从 0 开始,到 3 结束,不包括 3 。使用这种计数方式有一个重要的因素是方便计算字串的长度。字符串 s.substring(a, b) 的长度为 b-a. 例如上面例子中的字串 “Hel” 的长度是 3-0 = 3.
字符串拼接
与绝大多数的程序设计语言一样,Java语言允许使用+
(加号)拼接两个字符串。
String str1 = "Hello";
String str2 = "World";
String str = str1 + str2;
System.out.println(str); // HelloWorld
如果需要将多个字符串通过一个定界符连接在一起,可以使用 String 类中的静态方法 join.
String names = String.join("&", "张三", "李四", "王五");
// 运行结果:张三&李四&王五
不可变字符串
String 类没有提供修改字符串的方法。由于不能修改Java字符串中的字符,所以在Java文档中将 String 类对象称为不可变字符串。
对于Java中不可变字符串,可以这样理解:如同数字 3 永远是数字 3 一样,字符串 “Hello” 永远是字符串 “Hello”. 可以修改的是字符串引用指向的字符串对象,让他指向另一个字符串,如同将存放 3 的字符变量改成存放 4 一样。
字符串共享
Java字符串不可变的设计是为了实现字符串共享。Java的设计者认为共享带来的高效率远远胜过于提取、拼接字符串所带来的低效率。
String java = new String("Java");
上面的例子中,“Java” 称为字符串直接量。
对于Java程序中的直接量,JVM 会使用一个字符串池来保存。如果下一次用到同样的字符串,就会直接指过来而不再重新创建。(可以使用下面的程序测试)
String str1 = "Hello";
String str2 = "Hello";
System.out.println(str1 == str2);
// true
很明显,上面的程序比较的是 str1 和 str2 两个引用是否相等,即它们是否指向同一个对象。程序运行的结果是 true。说明 str1 和 str2 指向的 “Hello” 的确是同一个。(至于为什么判断字符串的内容是否相等应该使用 equals 而不是 ==,后面会解释原因)
String str = "Hello";
str = "Java";
Str = "JS";
不断使 str 指向其他对象,会导致之前的对象成为没有引用的内存垃圾,但是由于字符串直接量都是存放在字符串池中的,不会被 JVM 回收,这样很容易造成内存泄漏。
宏替换
如果字符串连接表达式的值可以在编译期确定下来,那么 JVM 会在编译时计算该字符串变量的值,并让它指向字符串池中对应的字符串。
Java中,一个用 final 定义的变量,不管它是什么类型的变量,只要使用了 final 定义并同时指定了初始值,并且这个初始值在编译的时候可以被确定下来,那么,这个 final 变量就是一个宏变量。编译器会把程序中所有用到该变量的地方直接替换成该变量的值。也就是说,编译器能对宏变量进行宏替换。
String str1 = "Hello World";
final String s = "Hello ";
String str2 = s + "World";
System.out.println(str1 == str2);
// true
但是,只有 final 修饰的量才能进行宏替换,如果上面的例子修改为
String str1 = "Hello World";
String s = "Hello ";
String str2 = s + "World";
System.out.println(str1 == str2);
// false
所以,对于Java中字符串内容是否相等的比较应该使用 equals 而不是 ==,因为不能保证用来做比较的字符串一定没有做过拼接运算。
String str = "Hello" + "!";
关于上面的语句,只创建了一个 String 类型的对象 “Hello!”,“Hello” 和 “!” 都是字符串直接量。
所以当程序中需要使用字符串、基本类型包装类的实例时,应该尽量使用字符串直接量、基本类型的直接量,避免通过 new String()|new Integer() 的形式来创建。这样能保证较好的性能。
字符串的比较
比较两个字符串的内容是否相同
"Hello".equals(str);
如果是变量和一个字符串直接量进行比较,建议将直接量写在前面,这样可以有效避免抛出空指针异常。
检测两个字符串是否相等而且不区分大小写
"Hello".equalsIgnoreCase("hello");
空串与 null
空串是长度为 0 的字符串,null 是对象类型的默认值。
检查空串
if (str.lengt() == 0) {
}
// 或者
if ("".equals(str)) {
}
检查 null
if (null == str) {
}
检查一个字符串既不是 null 也不是空串
if (null != str && str.length() != 0) {
}
先判断 str 是否为 null 也是为了避免出现空指针异常。