String可能是我们在平常使用中遇到概率最高的一个类了。今天我们就来聊聊关于这个类的一些常见坑位。
一、对象创建
首先来看下关于这个类的定义(jdk1.8版本):

由此我们可以得知:
1.String类不能被继承,因为类使用了final修饰
2.String的值存储是使用的char数组实现的
3.String的值不能被修改,因为char数组被final修饰
二、String、StringBuffer、StringBuilder的区别
1.值是否可变:
1)String是不可变
2)StringBuilder和StringBuffer是可变的(其内部的字符数组没有使用final修饰)
2.是否线程安全:
1)String中的对象是不可变的,也就可以理解为常量,是线程安全。
2)StringBuffer 中的方法大都采用了synchronized 关键字进行修饰,因此是线程安全的
3)StringBuilder 没有采用了synchronized关键字进行修饰,可以被认为是非线程安全的
三、常见问题
例子1:
public static void main(String[] args) {
String a="jack"
String b="jac"+"k"
System.out.println(a==b)
}
这个输出的是true.我们可以来看一下编译后的代码:
public static void main(String[] args) {
String a = "jack"
String b = "jack"
System.out.println(a == b)
}
当执行String a="jack"时,JVM首先会去字符串池中查找是否存在"jack"这个字面值的对象。如果不存在,则在字符串池中创建"jack"这个对象,然后将这个对象的引用地址返回给字符串常量a,这样a会指向池中"jack"这个字符串对象;如果存在,则不创建任何对象,直接将池中"jack"这个对象的地址返回,赋给字符串常量。当创建字符串对象b时,字符串池中已经存在"jack"这个对象,所以直接把引用地址返回给b,这样b也指向了池中"jack"这个对象。因此输出:true
例子2:
String name1=new String("rose")
String name2=new String("rose")
System.out.println(name1==name2)
这个执行的输出是false。因为使用new关键字新建对象的时候,是直接在堆上创建出对象的,不会比较对象的值是否已经存在。因而name1和name2的指向地址是不一样的。
例子3:
public static void main(String[] args) {
String a="ja"
String b="c"+"k"
String c=a+b
System.out.println(c=="jack")
String d="ja"+"ck"
System.out.println(d=="jack")
}
这里要注意的是,对于d而言,编译器就可以确定d的值是"jack",因而会相等。而c的赋值是在运行起才能确定,其实是对其进行new的处理。所以c的对象是创建在堆中的,所以和字符串"jack"不相等。