Java中的String,Stringbuffer和StringBuilder的区别

上一篇 / 下一篇  2012-05-11 11:27:13 / 个人分类:Java

众所周知string对象在java里面是不可变(immutable)的,任 何的连接,修改,其实都是在heap里面创建了一个新的string对象,而对原来的string对象是没有任何影响的,它们还是在那里,不曾改变,你只 是用它们的字面值去创造了新的strings而已。

string的不可变特性是非常有用的,至少这使得string是绝对的多线程安全的,那么java是怎么对待string对象的呢?是怎么利用string的这个不可变特性去优化内存的使用的呢?

我们从string的两种构造方式说起
String s1 = new String("tubie");
String s2 = "tubie";

有什么两样?两者最后都返回了一个指向字面值为tubie的一个引用,从这个结果来看是一样的,但其实过程和内存的变化都是大大的不同的

前者因为使用了new关键字,这迫使JVM在heap上创建了一个新的string对象,然后把该对象的引用返回,任务结束;
后者因为是"常量"赋值,所以其任务其实多了很多。JVM会首先到一个内部的string pool中找是否有存在相同值的string对象,这个string pool是java.lang.String内部维护的。如果有,就返回池里那个对象的引用,没有就在堆上分配个新的,然后把引用返回给用户的同时把这个 新的string,以前没有的string加到池里。

注意第一种方法虽然创建了一个string对象但是并没有放到池里,哪个对内存的利用率高清晰可辨,哪个在调用时的消耗大,做的事情多也清晰可见(哈希做的string pool搜索?)。空间和时间的trade off啊。

所以咯,如果之前string pool中没有"tubie"这个string,那么毫无疑问之前的s1 != s2,当然,equls的值比较是相等的,而这时如果有String s3 = "tubie";那么 S2 == S3是成立的了,因为池里已经加入了s2,并且在创建s3时搜到了。

前面说到用new关键字创建的string对象不会自己加入到string pool里面(在池里的string,有种叫法叫intern strings),那就要显示的由用户来加入

String sa = new String("Cao Dui");
sa = sa.intern();

这时候Cao Dui就加入到字符串池里面了。
这个intern到底做了哪些事?
首先查看了string pool,有没有一个"Cao Dui"已经加入过了,加入的那个直接返回给sa
不存在就在堆上另外分配一个"Cao Dui"的string对象,把sa指向这个,再把sa放入到池里。
无论是哪种情况,可以肯定的是,第一句的sa和第二句结束时的sa肯定是两个引用了。在这里第一个Cao Dui因为唯一的sa已经不指向它了,所以会很快被GC给回收掉。

我们另外从刚才的过程,intern函数的调用里可以得到一个结论,就是如果s1.equls(s2);则必定有s1.intern() == s2.intern();这时候s1和s2其实已经在这句比较结束后指向同一个已经在string池里面的对象了。

JVM这么做就是因为string的不可变特性。intern函数是一个native函数。

值得一说的是string的连接是创造了一个新的对象的。所以把sa和s1连接下,创建的就是一个完全新的string对象:
Cao Dui tubie


String的设计是一个典型的单一模式

String str1="AAAA";
String str2="AAAA";

这生成两个对象吗?
不是。在内存中,这是同一个对象
所以 
if(str1==str2){} 的结果应该是 true


如果要生成不同的对象,就必须
String str1=new String("AAAA");
String str2=new String("AAAA");
if(str1==str2){} 的结果应该是 false

用第一种做法虽然变量名变来变去,但内存中对象仍只有一个,这种方法可以有效地节省内存空间和提高运行效率。

由于String具有不变的性质。所以对一长串String中的每一个字符进行操作是比较浪费时间的,对String进行加减删除替换等工作比较耗时,所以后来Sun又推出来StringBuffer方法来做这些事情。
StringBuffer类似于一个char[],
所以对数组无素做遍历,删除,增加,修改,查找等工作是比较快速的,完成后再把StringBuffer可以转化成String

例: 
String a="请输入帐号:";
String b="NNNN";
String c="请输入密码:";
String d="XXXX";
............

一般的做法 String result=a+b+c+d;
结果是正确的,但不是高效的代码!


改良的做法:
StringBuffer buffer=new StringBuffer();
buffer.append(a);
buffer.append(b);
buffer.append(c);
buffer.append(d);
String result=buffer.toString();

TAG:

 

评分:0

我来说两句

我的栏目

日历

« 2024-05-12  
   1234
567891011
12131415161718
19202122232425
262728293031 

数据统计

  • 访问量: 5625
  • 日志数: 10
  • 建立时间: 2012-05-11
  • 更新时间: 2012-07-11

RSS订阅

Open Toolbar