JavaSE第三十讲:String类陷阱深度剖析
2012-11-22 20:50
417 查看
解读第二十八讲字符串的那个程序来充分理解字符串知识点:
D:\src>java ObjectTest2
false
------------------------
false
------------------------
true
------------------------
false
------------------------
false
------------------------
true
针对以上程序,我们进行对String类的剖析:
1. 查看JavaSE API文档String类说明:
The
of this class.
1):String类用final修饰,说明String类不能被继承了。
2):String类代表这一个字符串,Java程序中所有的字符串的字面值[literals],比如说“abc”本身也是String类的实例。
比如说上面程序String str3 = "bbb";其中“bbb”这个字面值也是用类的实例来表示的。
举以下例子:
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.equals(t)为true,则s.intern() == t.intern();为真。
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
Stringclass 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
sand
t,
s.intern() == t.intern()is
trueif and only if
s.equals(t)is
true.
如果且仅当s.equals(t)为true,则s.intern() == t.intern();为真。
相关文章推荐
- JavaSE第八十七讲:File类详解及使用陷阱深度剖析
- JavaSE第八十五讲:内部类深度剖析及常见使用陷阱
- String类陷阱深度剖析 -字符串池-栈-堆-equal--tostring--hashcod
- JavaSE第一百零二讲:synchronized关键字常见陷阱深度剖析
- Java记录 -25- String类深度剖析
- JavaSE第五十二讲:HashSet 与HashMap源代码深度剖析
- 【C++深度剖析教程17】逻辑操作符的陷阱
- JavaSE第九十九讲:Thread类源码深度剖析
- JavaSE第七十五讲:异常笔试、面试常见问题深度剖析
- JavaSE 第六十二讲: Class类、Method类及Field类的使用方式深度剖析
- JavaSE第六十七讲:InvocationHandler接口与Proxy类深度剖析
- JavaSE第一百讲:线程同步问题深度剖析
- Java记录 -25- String类深度剖析
- JavaSE第六十五讲:静态代理模式深度剖析
- JavaSE第二十九讲:String类源代码深剖析
- JavaSE第八十讲:监听器、事件、事件源、事件注册深度剖析
- JavaSE 第八十二讲:观察者模式深度剖析
- JavaSE第四十五讲:hashCode与equals深度剖析与源码详解
- JavaSE第一百零三讲:wait及notify方法全名、深度剖析
- 深度剖析CloudFoundry的架构设计