您的位置:首页 > 编程语言 > Java开发

JavaSE第三十讲:String类陷阱深度剖析

2012-11-22 20:50 417 查看
解读第二十八讲字符串的那个程序来充分理解字符串知识点:

public class ObjectTest2{
public static void main(String[] args){
Object object = new Object();
Object object2 = new Object();
System.out.println(object == object2);

System.out.println("------------------------");
String str = new String("aaa");
String str1 = new String("aaa");
System.out.println(str == str1);
//	System.out.println(str.equals(str1));

System.out.println("------------------------");
String str3 = "bbb";
String str4 = "bbb";
System.out.println(str3 == str4);

System.out.println("------------------------");
String str5 = new String("ccc");
String str6 = "ccc";
System.out.println(str5 == str6);

System.out.println("------------------------");
String s = "hello";
String s1 = "hel";
String s2 = "lo";
System.out.println(s == s1 + s2);

System.out.println("------------------------");

System.out.println(s == "hel" + "lo");

}
}
编译执行结果:

D:\src>java ObjectTest2

false

------------------------

false

------------------------

true

------------------------

false

------------------------

false

------------------------

true

针对以上程序,我们进行对String类的剖析:

1.   查看JavaSE API文档String类说明:

public final class String
extends Object
implements Serializable, Comparable<String>, CharSequence

The
String
class represents character strings. All string literals in Java programs, such as
"abc"
, are implemented as instances
of this class.


1):String类用final修饰,说明String类不能被继承了。

2):String类代表这一个字符串,Java程序中所有的字符串的字面值[literals],比如说“abc”本身也是String类的实例。

   比如说上面程序String str3 = "bbb";其中“bbb”这个字面值也是用类的实例来表示的。

举以下例子:

public class StringTest2{
public static void main(String[] args){
String s1 = "hello";
String s2 = " world";
String s3 = s1 + s2;

System.out.println(s3);
}
}
编译结果:

D:\src>java StringTest2

hello world

【说明】:Strings are constant; their values cannot be changed after they are created.【官方文档】

字符串是一个常量,当它们创建完值是不会被改变的,上面这个例子String
s1 = "hello";S1被创建完之后它们的值是不会变,同样s2的值也是不会变的,当执行String s3 = s1 + s2;的时候这种加法操作,是将字符串字面值hello与word拼接在一块然后再赋给新的对象引用s3,而不是对它们原有对象内容进行追加内容,这是学习String的误区,字符串字面值创建完成后是不能改变的。


2. String是常量,其对象一旦创建完毕就无法改变。当使用+拼接字符串时,会生成新的String对象,而不是向原有的String对象追加内容。 

3. String Pool(字符串池) 

4. String s = “aaa”;(采用字面值方式赋值) 

1) 查找 String Pool 中是否存在“aaa”这个对象,如果不存在,则在String Pool中创建一个“aaa”对象,然后将String Pool中的这个“aaa”对象的地址返回来,赋给引用变量s,这样s会指向String Pool中的这个“aaa”字符串对象。

2) 如果存在,则不创建任何对象,直接将String Pool中的这个“aaa”对象地址返回来,赋给s引用。

【说明】:所以上面程序String str3 = "bbb";String str4 = "bbb";执行过程中,由于str3已经在String Pool中创建一个“bbb”的对象了,str4由于检查String
Pool中已经有str3生成的那个“bbb”对象了,所以str4不再生成对象,直接把地址返回赋给str4,所以str4不再生成对象了,此时他们指向同一个对象,所以输出true。


5. String s = new String(“aaa”);

1) 首先在String Pool中查找有没有“aaa”这个字符串对象,如果有,则不在String Pool中再去创建“aaa”这个对象了,直接在堆中(heap)中创建一个“aaa”字符串对象,然后将堆中的这个“aaa”对象的地址返回来,赋给s引用,导致s指向了堆中创建的这个“aaa”字符串对象。 

2) 如果没有,则首先在String Pool中创建一个“aaa“对象,然后再在堆中(heap)创建一个”aaa“对象,然后将堆中的这个”aaa“对象的地址返回来,赋给s引用, 导致s指向了堆中所创建的这个”aaa“对象。

【说明】:所以上面程序String str = new String("aaa"); String str1 = new String("aaa");即便str在String Pool创建了“aaa”的对象,str1就String
Pool中不再创建“aaa”对象,但是会在堆中创建对象。即他们最终都会在堆(heap)中创建对象,然后把各自地址赋给str和str1。所以他们输出为false。


【注意】:String Pool是在内存栈中,如果是new出一个实例的话是在内存的堆(heap)中生成一个对象。这两个在内存中的位置是不一样的。




6. 继续查看String类官方JDK文档,查看其中的intern()方法,如下图30-1所示:



图30-1
          
【译】

   canonoical [标准]

返回一个字符串标准的表示。
一个字符串池,最初是空的,是由String类独自的去维护这个字符串池。
当这个intern()方法被调用,如果这个字符串池已经包含了一个字符串,并且这个字符串与调用intern()方法的字符串使用equals()进行比较,如果是相等,则来自字符串池的这个字符串就回返回。【比如,如果字符串池里面有”hello“,“hello”
与 “hello.intern()”两个比较,如果相等,则字符串池里面的"hello"就返回。】否则调用intern()的这个字符串对象就会被添加到池里面,而且这个字符串对象的引用就会被返回来了。


It follows that for any two strings
s
and
t
,
s.intern() == t.intern()
is
true
if and only if
s.equals(t)
is
true
.


如果且仅当s.equals(t)为true,则s.intern() == t.intern();为真。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: