您的位置:首页 > 职场人生

【黑马程序员】String和StringBuffer 的区别与应用!

2013-07-27 11:47 771 查看
----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

String是一个非可变类(immutable),非可变类的实例是不能被修改的,每个实例中包含的信息都必须在该实例创建的时候就提供出来,并且在对象的整个生存周期内固定不变,非可变类确实有着自身的优势,如状态单一,对象简单,便于维护。其次,该类对象对象本质上是线程安全的,不要求同步。此外用户可以共享非可变对象,甚至可以共享它们的内部信息。String类在java中被大量运用,甚至在class文件中都有其身影,因此将其设计为简单轻便的非可变类是比较合适的。
知道String是非可变类以后,我们可以进一步了解String的构造方式了。创建一个Stirng对象,主要就有以下两种方式:
String str1 = new String("abc");
Stirng str2 = "abc";
虽然两个语句都是返回一个String对象的引用,但是jvm对两者的处理方式是不一样的。对于第一种,jvm会马上在heap中创建一个String对象,然后将该对象的引用返回给用户。对于第二种,jvm首先会在内部维护的strings pool中通过String的 equels 方法查找是对象池中是否存放有该String对象,如果有,则返回已有的String对象给用户,而不会在heap中重新创建一个新的String对象;如果对象池中没有该String对象,jvm则在heap中创建新的String对象,将其引用返回给用户,同时将该引用添加至strings pool中。注意:使用第一种方法创建对象时,jvm是不会主动把该对象放到strings pool里面的,除非程序调用 String的intern方法。

public static void main(String[] args){
String str1=new String("abc");//jvm在堆上创建一个String对象
//jvm在Strings pool中找不到值为"abc"的字符串
//因此在堆上创建一个String对象,并将该对象引用加入至Strings pool中
String str2="abc";//此时堆上有两个Stirng对象
if(str1==str2){
System.out.println("str1==str2");
}else{
System.out.println("str1!=str2");
}
//打印结果是 str1 != str2,因为它们是堆上两个不同的对象
String str3 = "abc";//此时,jvm发现strings pool中已有“abc”对象了,因为“abc”equels “abc”
//因此直接返回str2指向的对象给str3,也就是说str2和str3是指向同一个对象的引用
if(str2==str3){
System.out.println("str2==str3");
}else{
System.out.println("str2!=str3");
}
}
}
输出:
str1!=str2
str2==str3
public static void main(String[] args){
String str1=new String("abc");//jvm在堆上创建一个String对象
str1 = str1.intern();
//jvm在Strings pool中找不到值为"abd"的字符串
//因此在堆上创建一个String对象,并将该对象引用加入至Strings pool中
String str2="abc";//此时堆上有两个Stirng对象
if(str1==str2){
System.out.println("str1==str2");
}else{
System.out.println("str1!=str2");
}
//打印结果是 str1 != str2,因为它们是堆上两个不同的对象
String str3 = "abc";//此时,jvm发现strings pool中已有“abc”对象了,因为“abc”equels “abc”
//因此直接返回str2指向的对象给str3,也就是说str2和str3是指向同一个对象的引用
if(str2==str3){
System.out.println("str2==str3");
}else{
System.out.println("str2!=str3");
}
}
}
输出:
str1==str2
str2==str3

String不属于8种基本数据类型,它String是一个对象,因为对象的默认值是null,所以String的默认值也是null;但它又是一种特殊的对象,有其它对象没有的一些特性。
new String()和new String("")都是申明一个新的空字符串,是空串不是null。
Stringstr="kvill"和String str=new String ("kvill");的区别:
先简单引入常量池这个简单的概念
常量池(constantpool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。
String s0="kvill";
String s1="kvill";
String s2="kv" + "ill";
System.out.println( s0==s1 );
System.out.println( s0==s2 );
输出
true
true
Java会确保一个字符串常量只有一个拷贝。
因为例子中的s0和s1中的"kvill"都是字符串常量,它们在编译期就被确定了,所以s0==s1为true;而"kv"和"ill"也都是字符串常量,当一个字符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,所以s2也同样在编译期就被解析为一个字符串常量,所以s2也是常量池中"kvill"的一个引用,所以得出结论s0==s1==s2。

用new String()创建的字符串不是常量,不能在编译期就确定,所以new String() 创建的字符串不放入常量池中,它们有自己的地址空间。
String s0="kvill";
String s1=new String("kvill");
String s2="kv"+new String("ill");
System.out.println( s0==s1 );
System.out.println( s0==s2 );
System.out.println( s1==s2 );
结果为:
false
false
false
s0还是常量池中"kvill"的应用,s1因为无法在编译期确定,所以是运行时创建的新对象"kvill"的引用,s2因为有后半部分new
String("ill")所以也无法在编译期确定,所以也是一个新创建对象”kvill”的应用;明白了这些也就知道为何得出此结果了。

String.intern():
字符串常量存在于.class文件中的常量池,在运行期被JVM装载,并且可以扩充。String的intern()方法就是扩充常量池的一个方法;当一个String实例str调用intern()方法时,Java查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的引用,如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用。intern的命令为:"把这个字符串放到常量池中去比对,如果找到了相同的字符串值,则这个引用会指向常量池中的字符串。"
String s0= "kvill";
String s1=new String("kvill");
String s2=new String("kvill");
System.out.println( s0==s1 ); //s0在常量池中,而s1不在,所以结果为false
System.out.println( "=====");
s1.intern(); //发现常量池中s0的值和s1相同,故返回s0的引用,但此处引用并没有被接收
s2=s2.intern(); //把常量池中"kvill"的引用即s0赋给s2
System.out.println( s0==s1);
System.out.println( s0==s1.intern() );
System.out.println( s0==s2 );
结果为:
false
=====
false //虽然执行了s1.intern(),但它的返回值没有赋给s1,即此时s1指向的还是常量池以外的那个值为"kvill的字符串"
true //说明s1.intern()返回的是常量池中”kvill”的引用
true
下例
String s1=new String("kvill");
String s2=s1.intern();
System.out.println( s1==s1.intern() );
System.out.println( s1+" "+s2 );
System.out.println( s2==s1.intern() );
结果:
false
kvillkvill
true
在这个类中我们没有声名一个”kvill”常量,所以常量池中一开始是没有”kvill”的,当我们调用s1.intern()后就在常量池中新添加了一个”kvill”常量,原来的不在常量池中的”kvill”仍然存在,也就不是“将自己的地址注册到常量池中”了。
s1==s1.intern()为false说明原来的“kvill”仍然存在;
s2现在为常量池中“kvill”的地址,所以有s2==s1.intern()为true。
5. 关于equals()和==:
这个对于String简单来说就是比较两字符串的Unicode序列是否相当,如果相等返回true;而==是比较两字符串的地址是否相同,也就是是否是同一个字符串的引用。
6. 关于String是不可变的
这一说又要说很多,大家只要知道String的实例一旦生成就不会再改变了,比如说:Stringstr=”kv”+”ill”+” “+”ans”;
就是有4个字符串常量,首先”kv”和”ill”生成了”kvill”存在内存中,然后”kvill”又和”“ 生成 ”kvill “存在内存中,最后又和生成了”kvillans”;并把这个字符串的地址赋给了str,就是因为String的“不可变”产生了很多临时变量,这也就是为什么建议用StringBuffer的原因了,因为StringBuffer是可改变的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: