读书人

关于String和StringBuffer的有关问题(

发布时间: 2012-01-02 22:40:04 作者: rapoo

关于String和StringBuffer的问题(好难呀,高手救我)
现在我有个问题
String s1= "hello world ";//(1)创建了几个对象?
String s2= "hello world ";//(2)在这点上又创建了几个对象?
String s3=new String( "hello world ");//(3)创建了几个对象?
String s4=new String( "hello world ");//(4)在这点上又创建了几个对象?
StringBuffer s5 =new StringBuffer( "hello world ");(5)创建了几个对象?
StringBuffer s6 =new StringBuffer( "hello world ");(6)在这点上又创建了几个对象?
String s7= "hello world! ";//测试用的
大写字母都是我找的资料 ;小写字母是我自己理解的
A equals 和 == 都是比较对象的地址;但是如果类中重载了equals(当然也不能忘了hashcode),就比较对象的值

B JAVA对String字面量的创建做一些优化,为了避免相同的字符串字面量被重复创建,它使用了String Pool,在String Pool中,存储了已经创建的字符串,所以,一个字符串字面量始终只创建一次.
C String s1 = new String( "abc ");
//创建二个对象, 一个是 "abc ", 一个是包裹 "abc "的String对象

String s2 = new String( "abc ");
//创建一个对象, 因为 "abc "已经被创建了, 不再重新创建

a:s1 与 s2 用 == 和 equals 符号 得的结果都是 true (String已经替我们重载了),也就是说 s1和s2在栈中创建了2个引用对象,但是在堆中只要是相同的内容就只创建一个 "hello world ",也的确如此(a)

疑问:s1 = s1 + '! '; 在拿s1与s7用==和equals比较的的结果就是 false和true了
我理解是这样的 (+) s1 = s1 + '! ' 和 s1 = (new StringBuffer(s1)).append( "! ").toString();是等效的。在new StringBuffer(s1)重新构造一个字符串缓冲区,所以导致了 符号(==)得的结果是false

c: s5 与 s6 用 == 和 equals 符号 得的结果都是 false 很明显堆中地址肯定不一样,equals也没有重载
String s1= "a ";
StringBuffer sb1=new StringBuffer( "a ");
StringBuffer sb2=sb1;
String s2=s1;
s1=s1+ '! ';
sb1.append( "b ");
System.out.println(s1==s2); flase
System.out.println(sb1==sb2); true
得到的结论是:而StringBuffer是可变长的字符串,不论怎么更动还是同一个字符串。

不好意思小弟刚学java还有很多不懂的地方,有理解不对的地方请原谅。哪位高手帮我看看 我总结的对不对 还有就是(1)--(6)分别创建了几个对象 ? 我对大写 C 的资料非常不理解。为什么说,s2那地方只创建了一个对象?


[解决办法]
String s1= "hello world ";//(1)创建了几个对象?
// One String is created in the pool and One String Reference Variable is created.

String s2= "hello world ";//(2)在这点上又创建了几个对象?
// One String Reference Variable is created.
//No additional String is created in the pool.

String s3=new String( "hello world ");//(3)创建了几个对象?
// One String Reference Variable is created.
// One String Object is created on the heap. No String created in the pool.

String s4=new String( "hello world ");//(4)在这点上又创建了几个对象?
// One String Reference Variable is created.
// One String Object is created on the heap. No String created in the pool.

StringBuffer s5 =new StringBuffer( "hello world ");(5)创建了几个对象?


// One StringBuffer Reference Variable is created.
// One StringBuffer Object is created on the heap. No String created in the pool.

StringBuffer s6 =new StringBuffer( "hello world ");(6)在这点上又创建了几个对象?
// One StringBuffer Reference Variable is created.
// One StringBuffer Object is created on the heap. No String created in the pool.

[解决办法]
LZ可能对为什么StringBuffer sb1,sb2对象进行修改后,其引用还相等,但是String s1 = "1 "; String s2=s1; s1 = s1 + "1 "; 这样的操作用,s1和s2就不相等了比较疑惑。

我们都知道java的两个对象如果直接用 "= "操作,是赋值引用,而不是对象。那么sb1,sb2无论对哪个做修改,他们的都指向同一个对象,那么总是相等的。

为什么String s1做修改后,原来的“引用”s2就不和s1相等了呢?
本来在做s2=s1的时候,两个都是引用指向同一个常量池地址。不产生新的对象。
可以看示范代码和编译的字节码:
代码:public void testStr() {
String s1 = "a ";
String s2 = s1;
}
字节码:
public void testStr();
Code:
Stack=1, Locals=3, Args_size=1
0: ldc #15; //String a 访问常量池#15
2: astore_1 //
3: aload_1
4: astore_2
5: return


稍微修改一下代码:
public void testStr() {
String s1 = "a ";
String s2 = s1;
s1 = s1 + "! "; //对s1做了操作
}

看一下字节码:
public void testStr();
Code:
Stack=3, Locals=3, Args_size=1
0: ldc #15; //String a
2: astore_1
3: aload_1
4: astore_2
5: new #17; //class java/lang/StringBuilder
8: dup
9: aload_1
10: invokestatic #19; //Method java/lang/String.valueOf:(Ljava/lang/Objec
t;)Ljava/lang/String;
13: invokespecial #25; //Method java/lang/StringBuilder. " <init> ":(Ljava/la
ng/String;)V
16: ldc #28; //String !
18: invokevirtual #30; //Method java/lang/StringBuilder.append:(Ljava/lang
/String;)Ljava/lang/StringBuilder;
21: invokevirtual #34; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
24: astore_1
25: return

第5行可以很清楚的看到编译出的字节码做了一个new java.lang.StringBuilder,然后再使用几个方法把常量池里的 "! " append 进去,再用toString返回回来,这个时候s1已经隐性指向到新的对象。

在Java程序中,有2大类实例化对象的方式:
一是显式的实例化:
(4种方式 new操作符 , 反射 newInstance() , 调用已有对象的clone方法, 反序列化 ObjectInputStream.getObject())

一是隐含的实例化:
1 在 main(String[] args) 方法中,保存命令行参数的String对象。
2 执行包含字符串连接操作符的表达式产生的对象。
3 Java虚拟机为每个装载的类型创建一个Class对象。


希望能解决LZ的疑惑:)


[解决办法]

JAVA对String字面量的创建做一些优化,为了避免相同的字符串字面量被重复创建,它使用了String Pool,在String Pool中,存储了已经创建的字符串,所以,一个字符串字面量始终只创建一次.
String s1 = new String( "abc ");
在String Pool中,存储了已经创建的字符串 "abc ",
so String s2 = new String( "abc ");
创建S2时直接引用在String Pool的 "abc "


读书人网 >J2SE开发

热点推荐