String类
String类表示字符串。Java程序中的所有字符串字面值
,比如“abc”,都是String的一个实例对象。
字符串是常量,一旦创建就不能修改
,因为字符串对象是不可变的,所以它们可以被共享。
创建String对象的两种主要方式:
- 字符串字面值
String s = “ShareBeHappy_Qin”;
- 使用 new 关键字
String s = new String (“ShareBeHappy_Qin”);
代码示例:
String str0 = "abc";
String str1 = "abc";
String str2 = new String("abc");
String str3 = new String("abc");
System.out.println(str0 == str1); // true
System.out.println(str1 == str2); // false
System.out.println(str2 == str3); // false
System.out.println(str1.equals(str2)); // true
System.out.println(str2.equals(str3)); // true
对于基本类型,== 是进行数值的比较。
对于引用类型,== 是进行地址值的比较。
字符串常量池
在JDK1.6以前,运行时常量池包含字符串常量池,即存在方法区中;自JDK1.7以后,运行时常量池就没有包含字符串常量池,运行时常量池存在于方法区中,而字符串常量池存在于堆中
。
当程序中直接写一个字符串(如 “abc”),在编译期就保存到字符串常量池中。
String str0 = “abc”;
这行代码表示:在栈中创建一个String类类型的引用变量str0,然后通过str0直接引用字符串常量池里面的"abc"对象,若常量池中不存在"abc"对象则先在常量池中创建再引用。
上面的代码中str0与str1都是指向常量池中的"abc"对象,所以变量当中的地址值是一样的。
String str2 = new String(“abc”);
这行代码创建了两个对象,在执行前会在常量池中查找是否有"abc"对象,若没有,则在常量池中创建一个"abc"对象;然后执行该行代码时,new关键字又创建一个"abc"对象存放在堆中;最后栈中的引用变量str2指向堆中的对象。
上面的代码中str2与str3都是通过new再堆中创建一个新的"abc"对象,所以两个变量当中的地址值不一样。
字符串拼接
由于String类的对象内容不可改变,所以每当进行字符串拼接时,总是会在内存中创建一个新的对象。
代码示例
public class StringDemo {
public static void main(String[] args) {
String s = "a"+"b"+"c";
}
}
分析代码,其实总共产生了五个字符串,即"a"
、"b"
、"c"
、"ab"
和"abc"
。引用变量s首先指向"a"
对象,最终指向拼接出来的新字符串对象,即"abc"
。
由此可知,如果对字符串进行拼接操作,每次拼接,都会构建一个新的String对象,既耗时,又浪费空间。为了解决这一问题,可以使用java.lang.StringBuilder
类。
StringBuffer、StringBuilder
三者的区别:
- String是不可变字符序列,StringBuilder和StringBuffer是可变字符序列。
- StringBuilder是不是线程安全的,建议在单线程中使用;StringBuffer是线程安全的。StringBuilder的运行速度比StringBuffer快。