String StringBuffer StringBuilder区别

string 字符串常量 
stringbuffer 字符串变量(线程安全) 
stringbuilder 字符串变量(非线程安全) 
简要的说, string 类型和 stringbuffer 类型的主要性能区别其实在于 string 是不可变的对象, 因此在每次对 string 类型进行改变的时候其实都等同于生成了一个新的 string 对象,然后将指针指向新的 string 对象,所以经常改变内容的字符串最好不要用 string ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, jvm 的 gc 就会开始工作,那速度是一定会相当慢的。 
而如果是使用 stringbuffer 类则结果就不一样了,每次结果都会对 stringbuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 stringbuffer ,特别是字符串对象经常改变的情况下。而在某些特别情况下, string 对象的字符串拼接其实是被 jvm 解释成了 stringbuffer 对象的拼接,所以这些时候 string 对象的速度并不会比 stringbuffer 对象慢,而特别是以下的字符串对象生成中, string 效率是远要比 stringbuffer 快的: 
string s1 = “this is only a” + “ simple” + “ test”; 
stringbuffer sb = new stringbuilder(“this is only a”).append(“ simple”).append(“ test”); 
你会很惊讶的发现,生成 string s1 对象的速度简直太快了,而这个时候 stringbuffer 居然速度上根本一点都不占优势。其实这是 jvm 的一个把戏,在 jvm 眼里,这个 
string s1 = “this is only a” + “ simple” + “test”; 其实就是: 
string s1 = “this is only a simple test”; 所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 string 对象的话,速度就没那么快了,譬如: 
string s2 = “this is only a”; 
string s3 = “ simple”; 
string s4 = “ test”; 
string s1 = s2 +s3 + s4; 
这时候 jvm 会规规矩矩的按照原来的方式去做 

在大部分情况下 stringbuffer > string 
stringbuffer 
java.lang.stringbuffer线程安全的可变字符序列。一个类似于 string 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。 
可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。 
stringbuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。 
例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append(“le”) 会使字符串缓冲区包含“startle”,而 z.insert(4, “le”) 将更改字符串缓冲区,使之包含“starlet”。 
在大部分情况下 stringbuilder > stringbuffer 
java.lang.stringbuilde 
java.lang.stringbuilder一个可变的字符序列是5.0新增的。此类提供一个与 stringbuffer 兼容的 api,但不保证同步。该类被设计用作 stringbuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 stringbuffer 要快。两者的方法基本相同。 
========================================================================= 
string类详解 
1、string类是final的,不可被继承。 
2、string类是的本质是字符数组char[], 并且其值不可改变。private final char value[]; 
然后打开string类的api文档,可以发现: 
3、string类对象有个特殊的创建的方式,就是直接指定比如string x = “abc”,”abc”就表示一个字符串对象。而x是”abc”对象的地址,也叫 

做”abc”对象的引用。 
4、string对象可以通过“+”串联。串联后会生成新的字符串。也可以通过concat()来串联,这个后面会讲述。 
6、java运行时会维护一个string pool(string池),javadoc翻译很模糊“字符串缓冲区”。string池用来存放运行时中产生的各种字符串, 

并且池中的字符串的内容不重复。而一般对象不存在这个缓冲池,并且创建的对象仅仅存在于方法的堆栈区。 

5、创建字符串的方式很多,归纳起来有三类: 
其一,使用new关键字创建字符串,比如string s1 = new string(“abc”); 
其二,直接指定。比如string s2 = “abc”; 
其三,使用串联生成新的字符串。比如string s3 = “ab” + “c”; 

二、string对象的创建 

string对象的创建也很讲究,关键是要明白其原理。 
原理1:当使用任何方式来创建一个字符串对象s时,java运行时(运行中jvm)会拿着这个x在string池中找是否存在内容相同的字符串对象, 

如果不存在,则在池中创建一个字符串s,否则,不在池中添加。 

原理2:java中,只要使用new关键字来创建对象,则一定会(在堆区或栈区)创建一个新的对象。 

原理3:使用直接指定或者使用纯字符串串联来创建string对象,则仅仅会检查维护string池中的字符串,池中没有就在池中创建一个,有则罢 

了!但绝不会在堆栈区再去创建该string对象。 

原理4:使用包含变量的表达式来创建string对象,则不仅会检查维护string池,而且还会在堆栈区创建一个string对象。 

另外,string的intern()方法是一个本地方法,定义为public native string intern(); intern()方法的价值在于让开发者能将注意力集中到 

string池上。当调用 intern 方法时,如果池已经包含一个等于此 string 对象的字符串(该对象由 equals(object) 方法确定),则返回池 

中的字符串。否则,将此 string 对象添加到池中,并且返回此 string 对象的引用。 

三、不可变类 
不可改变的字符串具有一个很大的优点:编译器可以把字符串设置为共享。 
不可变类string有一个重要的优点-它们不会被共享引用。 

是这样的,java为了提高效率,所以对于string类型进行了特别的处理---为string类型提供了串池 
定义一个string类型的变量有两种方式: 
string name= “tom “; 
string name =new string( “tom “) 
使用第一种方式的时候,就使用了串池, 
使用第二中方式的时候,就是一种普通的声明对象的方式 
如果你使用了第一种方式,那么当你在声明一个内容也是 “tom “的string时,它将使用串池里原来的那个内存,而不会重新分配内存,也就是说,string saname= “tom “,将会指向同一块内存 

另外关于string类型是不可改变的问题: 
string类型是不可改变的,也就是说,当你想改变一个string对象的时候,比如name= “madding ” 
那么虚拟机不会改变原来的对象,而是生成一个新的string对象,然后让name去指向它,如果原来的那个 “tom “没有任何对象去引用它,虚拟机的垃圾回收机制将接收它。 
据说这样可以提高效率!!! 
=========================================================================final stringbuffer a = new stringbuffer(“111”);  
final stringbuffer b = new stringbuffer(“222”);  
a=b;//此句编译不通过  
final stringbuffer a = new stringbuffer(“111”);  
a.append(“222”);//编译通过   
可见,final只对引用的”值”(即内存地址)有效,它迫使引用只能指向初始指向的那个对象,改变它的指向会导致编译期错误。至于它所指向的对象的变化,final是不负责的。 

string常量池问题的四个例子 
下面是几个常见例子的比较分析和理解: 

[1]  
string a = “a1”;   
string b = “a” + 1;  
system.out.println((a == b)); //result = true 
string a = “atrue”;   
string b = “a” + “true”;   
system.out.println((a == b)); //result = true 
string a = “a3.4”;   
string b = “a” + 3.4;   
system.out.println((a == b)); //result = true  
分析:jvm对于字符串常量的”+”号连接,将程序编译期,jvm就将常量字符串的”+”连接优化为连接后的值,拿”a” + 1来说,经编译器优化后在class中就已经是a1。在编译期其字符串常量的值就确定下来,故上面程序最终的结果都为true。 

[2]  
string a = “ab”;   
string bb = “b”;   
string b = “a” + bb;   
system.out.println((a == b)); //result = false  
分析:jvm对于字符串引用,由于在字符串的”+”连接中,有字符串引用存在,而引用的值在程序编译期是无法确定的,即”a” + bb无法被编译器优化,只有在程序运行期来动态分配并将连接后的新地址赋给b。所以上面程序的结果也就为false。 

[3] 
string a = “ab”;   
final string bb = “b”;  
string b = “a” + bb;   
system.out.println((a == b)); //result = true  
分析:和[3]中唯一不同的是bb字符串加了final修饰,对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中。 
所以此时的”a” + bb和”a” + “b”效果是一样的。故上面程序的结果为true。 

[4]  
string a = “ab”;   
final string bb = getbb();   
string b = “a” + bb;   
system.out.println((a == b)); //result = false   
private static string getbb() {  return “b”;   }   
分析:jvm对于字符串引用bb,它的值在编译期无法确定,只有在程序运行期调用方法后,将方法的返回值和”a”来动态连接并分配地址为b,故上面程序的结果为false。 

通过上面4个例子可以得出得知: 

string  s  =  “a” + “b” + “c”;      就等价于string s = “abc”; 

string  a  =  “a”;     
string  b  =  “b”;     
string  c  =  “c”;     
string  s  =   a  +  b  +  c;     
这个就不一样了,最终结果等于:  

stringbuffer temp = new stringbuffer();     
temp.append(a).append(b).append(c);     
string s = temp.tostring();   
由上面的分析结果,可就不难推断出string 采用连接运算符(+)效率低下原因分析,形如这样的代码: 

public class test {  
public static void main(string args[]) {  
string s = null;  
for(int i = 0; i }  
}   
每做一次 + 就产生个stringbuilder对象,然后append后就扔掉。下次循环再到达时重新产生个stringbuilder对象,然后 append 字符串,如此循环直至结束。 如果我们直接采用 stringbuilder 对象进行 append 的话,我们可以节省 n – 1 次创建和销毁对象的时间。所以对于在循环中要进行字符串连接的应用,一般都是用stringbuffer或stringbulider对象来进行append操作。 

string对象的intern方法理解和分析 
public class test4 {  
private static string a = “ab”;   
public static void main(string[] args){ 
string s1 = “a”;  
string s2 = “b”; 
string s = s1 + s2;  
system.out.println(s == a);//false  
system.out.println(s.intern() == a);//true   

}   
这里用到java里面是一个常量池的问题。对于s1+s2操作,其实是在堆里面重新创建了一个新的对象,s保存的是这个新对象在堆空间的的内容,所以s与a的值是不相等的。而当调用s.intern()方法,却可以返回s在常量池中的地址值,因为a的值存储在常量池中,故s.intern和a的值相等。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2553908.html

(0)
上一篇 2025年3月6日 06:52:13
下一篇 2025年3月6日 06:52:21

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • hibernate中多对多关系映射

    案例: person:一个人可以有担任很多项工作 job:一项工作可以由很多人担任 这在person和job中就形成了多对多的关系,映射成一张新表。 package com.pk.mapping;import java.util.HashS…

    编程技术 2025年3月6日
    000
  • ASP.NET session时间的设置

    asp.net session时间的设置 方法一:  asp.net session的默认时间设置是20分钟,即超过20分钟后,服务器会自动放弃session信息. 当我们在asp.net程序中打开webconfig的时候,可以看到一段如下…

    编程技术 2025年3月6日
    200
  • asp.net禁用按钮以防止重复提交

    方法一:  只在按钮前台代码中增加onclientclick=”this.disabled=true;” usesubmitbehavior=”false”即可。  方法二: protecte…

    编程技术 2025年3月6日
    200
  • asp.net默认回车按钮的设置

    其实一早就有接触过在asp.net的页面上如何设置默认的回车按钮,只是当时没有记录下来。今天再次碰上,翻资料找不到,按照网上的办法也解决不了,那叫一痛苦。          网上的办法相信大家都知道。无非都是在aspx页面上设置如下js代码…

    编程技术 2025年3月6日
    200
  • 关于URL后面传中文方法总结

    测试环境: 服务器tomcat5.0, 开发工具myeclipse6.5, 过滤器已经配置,编码utf-8。  方法一:修改tomcat配置  假设web服务使用8080作为端口,修改/conf/server.xml,增加红色这段   传值…

    编程技术 2025年3月6日
    200
  • Asp.net,C# 加密解密字符串

    首先在web.config | app.config 文件下增加如下代码:                                 iv:加密算法的初始向量。  key:加密算法的密钥。  接着新建类cryptohelper,作为加…

    编程技术 2025年3月6日
    200
  • Web Page的生命周期详解

    了解asp.net web page的生命周期对于一个做web开发的工程师来说很有必要,尤其是用于编写自己的control的时候。  asp.net web page的生命周期可以基本分为以下几个阶段:  1.  page request …

    编程技术 2025年3月6日
    200
  • 构造函数不能为虚函数

    构造函数不能声明为虚函数的原因:     1,所谓虚函数就是多态情况下只执行一个,而从继承的概念来讲,总是先构造父类对象,然后才能使子类对象,如果构造函数设为虚函数,那么你在构造父类的构造函数时就不得不显式的调用构造,还有一个原因就是为了防…

    编程技术 2025年3月6日
    200
  • 用C#生成不重复的随机数 – asp.net 教程

    我们在做能自动生成试卷的考试系统时,常常需要随机生成一组不重复的题目,在.net framework中提供了一个专门用来产生随机数的类system.random。  对于随机数,大家都知道,计算机不 可能产生完全随机的数字,所谓的随机数发生…

    编程技术 2025年3月6日
    200
  • c#.net常用的小函数和方法集

    1、datetime数字型system.datetime currenttime=new system.datetime();1.1取当前年月日时分秒currenttime=system.datetime.now;1.2取当前年int年=c…

    编程技术 2025年3月6日
    200

发表回复

登录后才能评论