一、字符串的比较
在开始讲解String之前先看看以下代码:
String a = new String("123"); String b = new String("123"); String c = "123"; String d = "123"; String e = a.intern(); System.out.println(a==b);//false System.out.println(c==d);//true System.out.println(a==c);//false System.out.println(a==e);//false System.out.println(c==e);//true
以上代码是简单的字符串的比较,后面的注释给出了相应的结果。下面我们来对执行结果进行相应的解释,首先执行a==b的结果很显然是false,因为是通过new关键字创造了两个不同的对象,这两个
对象都存储在堆空间中,a和b具有不同的引用,故为false,这里还要插一嘴:
String a = new String("123");
当执行到该代码时,实际上创建了两个对象,一个是由于String Pool 中并没有“123”这个字符串字面量,故会在String Pool中创建这个字符串对象指向“123”这个字符串字面量。另一个就是通过new关键字创建在heap 堆中的对象了。
接着来说说c==d,在这之前说一说String Pool,我们知道它代表的是字符串常量池,保存着像“123”这种的字符串字面量,在编译时期就确定被加入到String Pool中。很显然,c、d都是引用的String Pool中唯一存在的字符串字面量“123”,所有结果为true。a==c的结果也很显然了,一个的引用在堆中,一个的引用在String Pool中 故结果为false。现在来说一说a==e的比较结果,说这个之前我们要先了解了解intern()这个方法:
当一个字符串调用 intern() 方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法进行确定),那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。
现在我们再来看看,首先a.intern()的返回结果是String Pool中的“123”,而a引用的对象在堆中,故为a==e false. 所以最后一个c==e 就很好理解了,都是引用的String Pool中的“123”,故为true。
二、String类介绍
String 被声明为 final,因此它不可被继承。在 Java 8 中,String 内部使用 char 数组存储数据。
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; }
在 Java 9 之后,String 类的实现改用 byte 数组存储字符串,同时使用 coder
来标识使用了哪种编码:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final byte[] value; /** The identifier of the encoding used to encode the bytes in {@code value}. */ private final byte coder; }
value 数组被声明为 final,这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变。
说到String类,我们就会联想到StringBuffer和StringBuiler,String被定义为final,而StringBuffer和StringBuilder没有被定义为final,故为可变的。StringBuffer主要用来对字符串进行追加、拼接最后还是产生一个对象,而使用String对字符串进行拼接就显得有些繁琐并浪费空间。而StringBuilder和StringBuffer的唯一区别在于StringBuffer是线程安全的,使用了synchronized关键字来保证安全,这样也使得StringBuffer的效率低于StringBuider.
总结:
1. 可变性
- String 不可变
- StringBuffer 和 StringBuilder 可变
2. 线程安全
- String 不可变,因此是线程安全的
- StringBuilder 不是线程安全的
- StringBuffer 是线程安全的,内部使用 synchronized 进行同步
String中提供了许多的操作字符串的方法,这就需要大家自行去多多练习。