java字符串String类初探讨

关键词不可变对象 ;匿名对象;new字符串

1、不可变对象

      eg1:String s1 = "hello";

                s1.toUpperCase();

      该例中,调用的该方法并没有改变“hello”的值,而是创建了新的string类“HELLO”;然后将新的实例指向了s1.

2、匿名对象

      eg1:String s1 = "hello";

                String s2 = "hello"; 

      则我们可以很容易联想到 s1 ==s2;

      该例中,在堆内存创建了“hello”,然后在栈内存中,同时创建了两个实例指向了同一个堆内存对象。

3、new字符串

扫描二维码关注公众号,回复: 767450 查看本文章

      eg1: String s1 = new String("hello");

                 String s2 = new String("hello");

      该例中,利用new 对象同时在堆内存中开辟了两块内存,但都是同一个“hello”的匿名对象,因此在new s2的时候,原来的堆内存则变成垃圾,等待系统回收;

      上述举例同时说明了在java中字符串String的特殊性,即不可变特性。每当新建一个字符串对象时,则可在内存中开辟了空间,然后可以直接使用的对象。如果有新实例需要引用该字符串时,不会再内存中重新开辟空间,而是会将该实例直接复用此块内存。减少了不必要的空间开销;

关于String类不可变的优点总结:

    1.提高效率和安全性:在拷贝这个对象时,可以直接拷贝该内存地址,这样需要很小的开销,效率也高,同时还不会影响其他指向该String的实例;

    2.多线程的安全性:在多线程的情况下,可变对象的值可能会被其他进程改变,造成不可预期的问题,不可变对象则避免了该问题;

    3.同时,在创建String类时,它的Hashcode就已经计算好并缓存,不需要重新计算了,因此在使用Map时,将String设置为key效率会远远高于其它的键对象。

进一步:由于String是匿名不可变对象,那么 “+” 和StringBuilder的效率如何呢?

      eg:String_s1 +String_s2 ;

              StringBuilder   sb = new StringBuilder();

              sb.append(String_s1);

              sb.append(String_s2);

先说“+”: 在内存中,会开辟两块内存分别 存放String_s1 和String_s2.在编译的时候,“+”会变成 new StringBuilder().append(String_s1).append(String_s2).toString(),在最后会调用toString()方法,开辟一块新内存,存放新的String类,最后实例在内存中的指向会发生变化。导致“+”号连接符的效率低下;

而StringBuilder构建的是Builder类,会开辟一个16字符的内存缓冲区,如果后面添加内容大于16字符, Builder会扩充自己的缓冲区,在最后调用toString()时,则会拷贝builder的缓冲区,在内存中形成一个匿名String类,然后新实例会直接指向该区域。

在测试中,我们将0到100000之间的数字全部进行了拼接。分别比较“+”和“StringBuilder”效率,结果是“+”耗时42.67s,Builder耗时0.012s!!!

猜你喜欢

转载自marcoxiao.iteye.com/blog/2242537