站内搜索: 请输入搜索关键词

当前页面: 开发资料首页J2SE 专题String字符串的问题

String字符串的问题

摘要: String字符串的问题


String s1=-#34;abc-#34;;
String s2=-#34;abc-#34;;
String s3=new String(-#34;abc-#34;);
String s4=new String(-#34;abc-#34;);
System.out.println(s1==s2);
System.out.println(s3==s4);
System.out.println(-#34;abc-#34;==-#34;abc-#34;);
为什么会出来如下结果:
true
false
true
String s1=-#34;abc-#34;;和String s1=new String(-#34;abc-#34;);定义有什么区别吗?


String s1=-#34;abc-#34;;和String s1=new String(-#34;abc-#34;);
没有区别。。。。


这个问题是这样的,

首先,JAVA中String class是一个对象,所以在比较 == 符号时,两个String对象之间通过地址相互比较,即:只有同一个对象的两个引用之间的==比较才会产生true,所以
new String(-#34;abc-#34;) == new String(-#34;abc-#34;) is false
String a = new String(-#34;abc-#34;); String b = a; a == b is true

其次,String class覆写了Object class中的equals() method,这使得调用String.equals() method时,实际比较的是String class的内部值,而不是她的引用地址,所以
new String(-#34;abc-#34;).equals(new String(-#34;abc-#34;)) is true
new String(-#34;abc-#34;).equals(-#34;abc-#34;) is true
-#34;abc-#34;.equals(new String(-#34;abc-#34;)) is true

最后,String class在JAVA中是一个比较特殊的对象,由于她非常常用,并且可看做是一个char array,所以JAVA中对String class做了一些有趣的设计,以简化她的操作

1. 你可以通过 = 赋值符号来对String object进行赋值,而不必每次都使用new操作符生成一个新对象,所以简单的说
String str = new String(-#34;abc-#34;) 与
String str = -#34;abc-#34;;
等价

2. 但是以上二者又不完全等价,因为String太过常用,JAVA类库的设计者在实现时做了个小小的变化,即采用了享元模式,关于享元模式的具体内容可参见《设计模式 —— 四人帮的那本》或者《JAVA与模式——阎宏》,采取了享元模式后,每当生成一个新内容的字符串时,他们都被添加到一个共享池中,当第二次再次生成同样内容的字符串实例时,就共享此对象,而不是创建一个新对象,这样的做法仅仅适合于通过 = 符号进行的初始化,比如:
String str1 = -#34;abc-#34;; String str2 = -#34;abc-#34;;
str1 and str2 事实上共享了-#34;abc-#34;实例,所以 str1 == str2 is true
但是
String str1 = new String(-#34;abc-#34;),当使用new关键字后,JVM会强迫系统再次生成一个新的字符串实例而不是共享原先存在的实例,所以
String str2 = new String(-#34;abc-#34;)
str1 == str2 is false

为了保证共享对象后的数据一致性问题,类库的设计者还采取了不变模式来约束String对象。

最后,为了安全其间,对String对象的比较应该采用equals method而不是 ==,这样无论如何都不会发生比较问题,同时也可以防止因为分布式、持久化或者clone等操作后,导致对象被复制并无法返回期望的 == 结果。

@.@||~


因为String类比较特殊new的时候是在堆空间里面分配空间的返回的所以是一个地址所以s3!=s4
直接写的时候是在串池里面表示的当你在定义一个想同的对象的时候它会自己在池里面找如果没有才创建 有的话就直接返回它的地址 所以s1==s2
你可以用intern()方法得到堆里面对象的池地址比如s3=s3.intern();这个时候s1==s2==s3其实都是同一个对象


如果我再回答,分就不够分了。哈哈!


有区别的


没有区别的,我说错了,不好意思。


显然有区别啊 对象在的空间都不一样怎么会没有区别呢?回去吧final理解下 在看下设计模式的(强不变模式)String类就是一个强不变模式


1楼的对于String类 理解不够透彻 也没有考虑到池的问题

Java中很多地方都用到池的


学习了!


两者肯定有区别的,
String s1=-#34;abc-#34;;
String s2=-#34;abc-#34;;//这里只有一个对象;s1,s2是共享一个常量对象
String s1=new String(-#34;abc-#34;);//这是在堆中实实在在new一个对象;



在JVM中有串池这个概念,
当你不是用new 的方法创建的String对象,有相同的值的时候对应的是串池中的同一个值所以地址是同一个,用==比较的是两个对象的地址所以第一个是true
用new 生成的String对象是在堆空间生成的两个不同的String对象 自然物理地址是不一样的所以用==比较一定是不同的
至于第三个同第一个一样,String s1=-#34;abc-#34;;方式会在串池中生成的一个字符串,当你不用他的时候他不会被垃圾回收,而是在系统执行垃圾回收前一直存在着。System.out.println(-#34;abc-#34;==-#34;abc-#34;);它其实比较的是同一个对象,所以一定也是true的



上 更正:物理地址不准确
改为:在内存中的存储地址


这样搞迟早会疯掉的。。。。^_^



不要乱迷惑人。。。。

本身这个问题就不严密。。。。。。

回答的是楼主想得到的答案。。。。。

从哲学上讲任何两个东西都不一样。。。。。


主要要理解的是内存指向问题。
不用new关键字的,是把变量指向常量内存,比如前面两个
String s1=-#34;abc-#34;;
String s2=-#34;abc-#34;;
它们是建立s1和s2的隐式对象,指向“abc”这个常量的内存
当你用new关键字的时候,如后面两个
String s3=new String(-#34;abc-#34;);
String s4=new String(-#34;abc-#34;);
就创建事例对象s3和s4,并且把“abc”指向对象s3和s4

而“==”运算符的作用(一定程度上讲)就是比较他们的内存空间是否相同的,我们看前面两个建立的,他们的内存空间都是一样的在“abc”这个常量里面,所以他们是相同的内存空间;而后面两个是自己的内存,并且把常量“abc”指向自己,其实s3和s4就不是同个内存了,那么就会出现以下效果:
s1=s2 true 相同内存
s1=s3 false 不同内存
s3=s4 false 不同内存
s1=-#34;abc-#34; true 相同内存
s3=-#34;abc-#34; false 不同内存

这样说你应该明白了吧???



java为了效率的考虑,使用-#34;....-#34;的方式的字符串会在编译时直接放入到文字池中,而运行时文字池成为了常量池的一部分.使用文字池的好处在于:对于相同的字符串常量会进行合并,在文字池中只占用一个空间.

String a = -#34;hello-#34;;
String b = -#34;hello-#34;;
System.out.println(a==b);

由上可知:代码输出结果 true

而对于new String(-#34;....-#34;)的形式,本来-#34;...-#34;已经就是一个字符串对象,并存在于文字池中,而new String()会将文字池中的-#34;....-#34;拷贝到堆(heap)中,并把堆(heap)中对象的引用交给字符串引用变量.所以这条语句会产生两个 String对象.

String c = new String(-#34;hello-#34;);
String d = new String(-#34;hello-#34;);
System.out.println(c==d);

由上可知:代码输出结果为 false,引用变量c,d分别指向的是堆(heap)中不同的字符串对象.

详细的见我的blog:http://blog.csdn.net/nirvana_li/archive/2006/07/21/952240.aspx


大哥们这题只有两分来,我该怎么给,你们说的都不错,我很满意....谢谢...


学习了












深圳java程序员博客,为你提供多方面资料http://drivemewild.blogchina.com


换汤不换药,只是形式不用而已


.NET中MSDN称其为拘留池。

即所有编译时的string都会放在拘留池中,由于string是恒定不可改变的,所以编译时如果值一样,则从拘留池返回同一个对象,而不创建新对象。(Java中new方法可以明确地创建新对象。.NET没有此方法。)

这些只是在编译时发生,运行时对象不经过特殊方法不会放在拘留池。


虽然我也想到了,但觉得还midthinker给的答案最详细,最专业。那我就顶一下吧。


上述字符串的内容虽然相同,但由于他们使用了new关键字创建了两各对象s3 s4,所以s3 s4引用的对象并不同 所以为false


mark


收获不小,学习了!


String s1=-#34;abc-#34;;
String s2=-#34;abc-#34;;
//s1,s2是同时引用字符串-#34;abc-#34;的参考值

String s3=new String(-#34;abc-#34;);
String s4=new String(-#34;abc-#34;);
//s3,s4是不同的对象 ,因为new了

System.out.println(s1==s2);
//== 是比较两个对象是否相等 此处为同一对象,因此结果为true
System.out.println(s3==s4);
//不同对象 结果为false



哎~~很明显是有区别的嘛?
String str1=-#34;123-#34;; //创建了一个对象 123
String str2=-#34;abc-#34;; //创建了两个对象 一个abc 一个指向abc的引用str2

如果再定义一个String str3=-#34;123-#34;; 其实str1 和 str3是指向同一个对象的


我才学JAVA,之前认为==只有在使用同一个内存地址下才成立,大师们的解释发现我错了……
谢谢了


rypgood(失魂) 的解释不错,很清楚


midthinker的解释多,但是不精,没有说到点子上。rypgood的答案更利于理解,更精辟。





其实理解这个问题就是从内存角度去理解,因为==是比较对象引用句柄的值的,所以rypgood回答的好
看下面的语句:
                String str1= -#34;abc-#34;;//str1存放-#34;abc-#34;的首地址
String str3= -#34;abc-#34;;//str1存放-#34;abc-#34;的首地址
等效于
                char data[]={`a`,`b`,`c`};
String str1=new String(data);
                String str3=new String(data);
    但是在下面的这几条语句中的str1和str3却是不同的。问题出在 String(char[] value)这个构造函数。因为构造了两次,所以每次分配的堆内存必然是不相同的。这就导致了栈内存中表示堆内存首地址的str1,str3是不同的。这就是LZ为什么s3==s4 false
s1==s2 true的原因。


String s1=-#34;abc-#34;;
String s2=-#34;abc-#34;;
String s3=new String(-#34;abc-#34;);
String s4=new String(-#34;abc-#34;);

-#34;abc-#34;是个字符串,s1,s2都指向了他,所以相等

s3里的“abc”仅仅是内容,这里的“abc”只属于s3,s4与s3相同,都是独立的引用
所以他们不相等


真是高手如云啊,小弟刚来就对各位的见解非常佩服了,很喜欢和大家探讨。


s1 --#62; -#34;abc-#34;

s2 -----


s1,s2 是 refrence, 值相同也就是指向同一存储区域
s1==s2
java 以new 显式指出分配空间的动作,所以new出来的两个对象分别指向不同的两块存储区
s3!=s4



这个问题 midthinker(呵呵) 已经解释得很清楚了,还有必在讨论下去吗?要是解释成这样都还不明天,那就还是改行算了,因为JAVA中还存在着比这个问题复杂很多少倍的问题。


同意midthinker(呵呵)


-#34;==-#34;表示比较关系


-#62; 大哥们这题只有两分来,我该怎么给,你们说的都不错,我很满意....谢谢...

先加分,再结贴,hehe


好帖,收藏起来慢慢看……


↑返回目录
前一篇: Java EE 5 与 J2EE 1.4有什么区别?
后一篇: 一个奇怪的加密问题