转自:
作者: Betayao
出处:https://blog.csdn.net/weixin_35713860/article/details/82766350
对其中一些地方加入了自己的思考和整理,供自己和同学们学习参考。
StringBuilder
JDK官方文档里是这样说的:一个可变的字符序列。 此类提供与StringBuffer的API,但不保证同步。 此类设计用作简易替换为StringBuffer在正在使用由单个线程字符串缓冲区的地方(如通常是这种情况)。 在可能的情况下,建议使用这个类别优先于StringBuffer ,因为它在大多数实现中将更快。 简单来说:StringBuilder是StringBuffer的特殊优化版本,不考虑线程安全,效率最高。
当字符串相加操作或者改动较少的情况下,建议使用 String str="hello"这种形式;当字符串相加操作较多的情况下,建议使用StringBuilder,如果采用了多线程,则使用StringBuffer。
性能总结
- String对于直接相加字符串,效率很高,因为在编译器便确定了它的值,也就是说形如"I"+“love”+“java”;的字符串相加,在编译期间便被优化成了"Ilovejava"。这个可以用javap -c命令反编译生成的class文件进行验证。对于间接相加(即包含字符串引用),形如s1+s2+s3; 效率要比直接相加低,因为在编译器不会对引用变量进行优化。
- String、StringBuilder、StringBuffer三者的执行效率:
StringBuilder > StringBuffer > String
当然这个是相对的,不一定在所有情况下都是这样。比如String str = “hello”+ "world"的效率就比 StringBuilder st = new StringBuilder().append(“hello”).append(“world”)要高。
常见面试题
- 下面这段代码的输出结果是什么?
String a = "hello2";
String b = "hello" + 2;
System.out.println((a == b));
答:true。为什么呢?因为"hello" + 2在编译期间被优化成了"hello2",故运行期间a、b指向的是保存在常量池中的同一对象。
- 下面这段代码的输出结果是什么?
String a = "hello2";
String b = "hello";
String c = b + 2;
System.out.println((a == c));
答:false。由于有引用符号的存在,所有b + 2不会再编译期间被优化,不会吧b + 2当做字面常亮来处理,这种生成对象是保存在堆上。而a的对象是在常量池中。故a和c指向的并不是同一个对象。
- 下面这段代码的输出结果是什么?
String a = "hello2";
final String b = "hello";
String c = b + 2;
System.out.println((a == c));
答:true。对于被final修饰的变量,会在class文件常量池中保存一个副本,也就是说不会通过连接而进行访问,对final变量的访问在编译期间都会直接被替代为真实的值。那么String c = b + 2;在编译期间就会被优化成:String c = “hello” + 2。
- 下面这段代码输出结果为:
public class Main {
public static void main(String[] args) {
String a = "hello2";
final String b = getHello();
String c = b + 2;
System.out.println((a == c));
}
public static String getHello() {
return "hello";
}
}
答:false。这里面虽然将b用final修饰了,但是由于其赋值是通过方法调用返回的,那么它的值只能在运行期间确定,因此a和c指向的不是同一个对象。
- 下面这段代码的输出结果是什么?
public class Main {
public static void main(String[] args) {
String a = "hello";
String b = new String("hello");
String c = new String("hello");
String d = b.intern();
System.out.println(a==b);
System.out.println(b==c);
System.out.println(b==d);
System.out.println(a==d);
}
}
答:false false false true。在String类中,intern方法(intern详解)是一个本地方法,在JAVA SE6之前,intern方法会在运行时常量池中查找是否存在内容相同的字符串,如果存在则返回指向该字符串的引用,如果不存在,则会将该字符串入池,并返回一个指向该字符串的引用。因此,a和d指向的是同一个对象。