String的那些事儿
1、String的两种创建方式
在java中String的创建有两种方式,第一种是双引号直接创建,第二种是用构造函数创建,这两种方式有什么异同呢?看如下代码:
public class Test {
/**
* 字符串比较
*/
public static void main(String[] args) {
// a和b被分配到永久区(方法区)的运行时常量池的相同的内存
String a = "abc";
String b = "abc";
// c和d被分配到堆中的两个不同对象
String c = new String("abc");
String d = new String("abc");
//(1)
System.out.println(a == b);//结果:true
//(2)
System.out.println(a.equals(b));//结果:true
//(3)
System.out.println(c == d);//结果:false
//(4)
System.out.println(c.equals(d));//结果:true
//(5)
System.out.println(a == c);//结果:false
//(6)
System.out.println(a.equals(c));//结果:true
}
}
在(1)中,a== b等于true 是因为a和b指向方法区中同一个字符串常量,他们的引用是相同的(==比较的是引用)。
当相同的字符串常量被多次创建时,只会保存字符串常量的一份副本,这称为“字符串驻留”。在Java中,所有编译时字符串常量都是驻留的。
在(3)中,c== d等于false 是因为c和d指向堆中不同的对象。不同的对象拥有不同的内存引用。
在(4)中,c.equals(d)比较的是两字符串的内容是否相同。
下图论证了以上的结论:

2、String类是如何实现不可变的
String类的一大特点,就是使用Final类修饰符。Final类中的方法将永远不会被重写。
在Java中,String是被设计成一个不可变(immutable)类,一旦创建完后,字符串本身是无法通过正常手段被修改的。
3、String类设计成不可变的好处
我们都不是Java语言的设计者,不知道其为何一定要设计成不可变,试着做一些猜想。
1、可以实现多个变量引用JVM内存中的同一个字符串实例。
2、安全性,String类的用途实在太广了,如果可以随意修改的,是不是很恐怖。
3、性能,String大量运用在哈希的处理中,由于String的不可变性,可以只计算一次哈希值,然后缓存在内部,后续直接取就好了。如果String类是可变的话,在进行哈希处理的时候,需要进行大量的哈希值的重新计算。
4、扩展问题:String、StringBuffer和StringBulder的区别
String:
String类是一个final类,创建的字符串对象具有不变性。在字符串创建时若不使用new关键字,会在常量池中先进行查找,若常量池中存在,则直接将其内存地址赋给String
StringBuffer:
StringBuffer类创建的字符串对象会在内存中分配一个缓冲区,当我们要对它构建的字符串对象添加字符时,会在缓冲区中进行字符的追加。若需要对字符串进行频繁的修改时,可以使用StringBuffer从而节省内存。另外,StringBuffer实现了线程同步,可在多线程模式下使用,具有多线程安全性。
StringBuilder:
StringBuilder用法与StringBuffer相同,但是未能实现线程同步,不具有多线程安全性,故主要使用在单线程模式下!