Java String StringBuffer StringBuilder浅析

最近接触Android开发,凭着几年Java开发的经验,勉强接下了这个职位,又回到Java了,最大的感受是思考必须更加全面,想好了再做,再不能像写弱类型脚本语言那样,边做边写,写了再改了。

回忆下从业中接触的几年Java开发。03年实习中开始写Java,还记得入职第一个东西是个简单的编辑器,AWT做的界面,一边捧着 Thinking in Java, 一边敲代码,一起实习的同学还有专门买了本Java 类库的书,当然现在肯定没有了。当时除了学校里的的Java课程,本博还报了一门SCJP,厚厚的Java 2教程,好怀念。。。

先来看看几个基础的概念: String , StringBuffer, StringBuilder

String 定义

字符串类,2种形式定义,可以是基础数据,可以是类,区别是,举个栗子

String a = "xx";
String b = "yy";
a == b //True
a.equals(b)  //True

String a = new String("xx");
String b = new String("yy");
a == b //False
a.equals(b)  //True

String 是不可变的

String 是个final 类,因此对String 的操作,append等,其实是新建 String对象,舍弃原来的对象,并非改变。

String 在被设计的时候,作为一种基础类型,在Heap中,假设有个 String x, 值为 abc, 那么,String x 存一个 abc 的内存地址,然后 x 指向 这个内存地址, 因此,假设又有个String y, 那么 JVM的做法是,y 也会有个reference 指向这个内存地址, 注意,是同一个内存地址。因此,效率提高了,但是,为了同步,String就变成不可变了。

另一个场景,某 HashMap 内部,存储 hash值,必须永远一致,hash值就是一个String,如果不是定长的,直接调用内存的,那每次取,都必须要重算,重新开辟内存空间,那就比较伤资源了。

定长类,是线程安全的。

String 作为方法参数,也是值传递的

虽说传的是String 变量,粗看代码

public static void main(String[] args) {
    String x = new String("ab");
    change(x);
    System.out.println(x);
}

public static void change(String x) {
    x = "cd";
}

x 是String 类,这里很迷惑人,x 是指针,被拷贝了,变成 change 里面的 x, 此x 非彼x,而指正所指的是同一个内容,因此,貌似会变,但是不然。

事情是这样的,String x 存的是 指向 内存里 ab 的 一个内存地址,因此change里的 x, 其实确实是拷贝了 作为指针的x, 就是 change 里的 x 变成一个新的 指向 ab 的 内存地址的 指针, 也就是说 外面的 x 是个 内存地址, 这个内存地址,指向 heap 里的 “ab”, change里面的 x ,也是个内存地址,这个地址指向 heap 里的 “ab”, 注意,String 不可变, change 里的x 变成 “cd”,其实是change 里的x ,它所拥有的 那个内存地址,从指向 “ab”,变成了 “cd”,因此,于方法外的 x, 没半毛钱关系。。。

StringBuffer

这个比较简单,看字面意思,buffer, 就是这个String, 是一段buffer,因此是可以改变的,例如拼接。

StringBuffer 是线程安全的,是同步的,因为同步,所以耗费点时间

StringBuilder

也是可变的,但是是线程不安全的