String&StringBuffer的区别

 
String&StringBuffer的区别
相信有过java面试经历的朋友都知道,有一道题目是面试官们最喜欢问的内容之一,那就是请说明String&StringBuffer的区别。估计几乎所有参加过面试的同行都回答过此问题。到底是什么原因使面试官们对这个题目如此的情由独中呢?到底这两者有什么不同呢?下边就来探讨一下这个问题:
打开JDK的API,可以看到:public final class String extends Object implements Serializable、public final class StringBuffer extends Object implements Serializable。从这两个类的定义来看,没有任何区别,都是final类,不允许有别的类继承。
好了,我们来看一下区别。Sun官方给出的解释是:String类表示字符串,字符串是常量,它们的值在生成后不允许被改变;StringBuffer类表示字符串缓冲区,实现可变字符串序列。还给出了例子,如下:
1)        String str = “abc”;
等价与:
Char[] data ={‘a’,’b’,’c’};
String str = new String(data);
2)        x = ‘a’+4+‘c’
被编译成等价的:
x = new StringBuffer().append(“a”).append(4).append(‘c’).toString();
从JDK的API来看,好像没有什么特殊之处,不就两个普通的类嘛!面试官到底是出于什么目的来问这个问题呢??我们从几个例子来看一下它们深层次的区别,如下:
1.                   JDK的API中说的很清楚,String类表示的字符串在生成后是不允许被改变的。但是平时会经常看到诸如:
String str1 = “abc”;
str1 = str1 + “def”;
此类的情况。这时候就需要想一下了,API中不是说不允许被改变吗?这种情况平时好像也没有报什么错误!运行无误啊!Why??事实上,String str1 = “abc”;是建立一个str1的引用,使其指向String类型的对象”abc”;而str1 = str1 + “def”;这句并不是把”abc”对象的值改变成了”abcdef”,而是又新建了个String类型的对象”abcdef”,因此这两句执行完后内存中会有两个String类型的对象,一个是”abc”,两一个是”abcdef”,str1指向”abcdef”。对象”abc”的值自始至终都没有改变。
再看一下StringBuffer的这种情况,测试代码如下:(注释部分为输出结果)
           StringBuffer str1 = new StringBuffer(“abc”);
                 System.out.println(“str1=”+str1);   //str1=abc
           StringBuffer str2 = str1.append("d");
           System.out.println("str1="+str1);   //str1=abcd
           System.out.println("str2="+str2);   //str2=abcd
           System.out.println(str1==str2);    //true
            System.out.println(str1.equals(str2)); //true
                        从上边的测试结果能清楚的看到:StringBuffer的相加并不是像String那样新建了对象,而是在原来对象上直接修改,从代码的第6行可以看到str1和str2指向同一个对象(注:==表示内存地址的比较,即表示是否指向同一对象)。因此上边六句代码执行完后,内存种只有一个对象,显然效率要比String相加要高。因此如果字符串的内容经常变化的话,还是用StringBuffer效率比较高,最后可以通过toString()方法转换为String。
                   结论:String表示的字符串不能改变;而StringBuffer可以。
2.               说一下String特有的一种现象,看以下代码:(注释部分为输出结果)
String str1 = "abc";
String str2 = "abc";
String str3 = new String("abc");
String str4 = new String("abc");
System.out.println(str1==str2); //true
System.out.println(str1==str3);       //false
System.out.println(str3==str4);      //false
System.out.println(str1.equals(str2));    //true
System.out.println(str1.equals(str3));    //true
System.out.println(str3.equals(str4));    //true
对于以上的结果,有没有觉得很奇怪?
这里我们主要是要知道String str1 = “abc” ; String str = new String(“abc);它们两个看似一样,实际上是有很大区别的。不用new产生的String对象实际上是建立在常量池(内存中的一块区域)的,是属于编译器常量,即在所在类编译的时候就分配好了内存,随class文件一起载入,当另一个内容一样的字符串(String str2 = “abc”)建立时,编译器并不会去再分配内存,而是先在常量池中找与该字符串匹配的对象,如果找到则str2指向找到的对象,如果找不到,再在常量池中分配内存,所以在上边的第5行输出结果为true。用new产生的对象则属于执行期对象,它只有在程序执行中才去建立对象分配内存,因此每此new一个对象就会分配一块内存,所以上边第7行输出结果为false,当然第6行也应该为false。后边的三个比较都是比较的字符串内容,因此都为true。
结论:String str1 = “abc” ; String str = new String(“abc);是不同的。
3.               传值和传引用的问题:
看以下代码:
public static void main(String[] args){
String str1 = "abc";
StringBuffer str2 = new StringBuffer("abc");
System.out.println(“before dealwith,str1=”+str1);
dealWith(str1);
System.out.println(“after dealwith,str1=”+str1);
System.out.println(“####################”);
System.out.println(“before dealwith,str2=”+str1);
dealWith(str2);
System.out.println(“after dealwith,str2=”+str1);
}
private static void dealWith(String s){
    s = "def";
    System.out.println(“in dealWith,change String value ,str1=”+s);
}
private void dealWith(StringBuffer s){
    s.append("def");
    System.out.println("in dealWith ,change StringBuffer value, str2="+s);
}
输出结果如下:
before dealwith,str1=abc
in dealWith,change String value ,str1=def
after dealwith,str1=abc
####################
before dealwith,str2=abc
in dealWith ,change StringBuffer value, str2=abcdef
after dealwith,str2=abcdef
相信细心的朋友已经看出了区别,即Stirng对象在做为引数传递的是值,而StringBuffer则传递的是引用,所以才会出现了String对象在被调用函数内被修改却在调用函数中没有改变的现象,从这里可以看出通过String建立的虽然是一个对象,却在此处不具有对象的特征,而符合了Java中基本型别的特性(即传值,拷贝副本),这就是String的特殊之处。
结论:Stirng对象在做为引数传递的是值,而StringBuffer则传递的是引用。
以上简单探讨了String&StringBuffer的区别,有什么不准确的地方,欢迎大家批评指正,也请大家能够补充。
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值