String StringBuffer StringBuilder详细分析和面试题
从String类源码中了解String
1.String类是final类,表示终态类,不可继承,不可修改。
早期,被final修饰的方法会被转化为内嵌调用以提升效率,Java SE5/6以后,该方式被摒弃。故,这样定义的原因是不想让该方法被覆盖。
2.String类是通过char数组保存字符串。
再看看substring()方法和concat()方法:
对String对象的任何改变都不会影响原有对象,任何改变对象的操作都会生成一个新的对象,这一点从成员方法value用final修饰,可以看出
- final修饰类时,被修饰的类不能被继承;
- finale修饰变量时,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
那为什么说String不可变,而StringBuffer可变呢?
String不可变是说String中用一个final 的char数组 private final char value[]; 保存字符序列。用final修饰的对象值可变,但是引用不变,即:value指向不可变,但是value[]数组的值可变,但因为有private关键字对其进行封装达到value[]数组值也不可变的目的。
StringBuffer
StringBuffer类也被定义成final类,与String类相同。
但是StringBuffer类对象的字符序列是可修改的,类本身写好了方法改变序列类容和长度。
并且StringBuffer是线程安全的,类的各个方法都用synchronized修饰。
可以这样理解StringBuffer类:可修改的String,并且线程安全。(线程安全带来的缺点是效率相对StringBuilder而言更低)
StringBuilder
此类设计用作简易替换为StringBuffer在正在使用由单个线程字符串缓冲区的地方(如通常是这种情况)。
在可能的情况下,建议使用这个类别优先于StringBuffer ,因为它在大多数实现中将更快。
简单来说:StringBuilder是StringBuffer的特殊优化版本,不考虑线程安全,效率最高。
性能总结
- 对于直接相加字符串,效率很高,因为在编译器便确定了它的值,也就是说形如"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 str="hello"这种形式;当字符串相加操作较多的情况下,建议使用StringBuilder,如果采用了多线程,则使用StringBuffer。