﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava--文章分类-java基础</title><link>http://www.blogjava.net/dodoma/category/9063.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 12:30:41 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 12:30:41 GMT</pubDate><ttl>60</ttl><item><title>对String类的深刻理解 </title><link>http://www.blogjava.net/dodoma/articles/37779.html</link><dc:creator>dodoma</dc:creator><author>dodoma</author><pubDate>Tue, 28 Mar 2006 05:19:00 GMT</pubDate><guid>http://www.blogjava.net/dodoma/articles/37779.html</guid><wfw:comment>http://www.blogjava.net/dodoma/comments/37779.html</wfw:comment><comments>http://www.blogjava.net/dodoma/articles/37779.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dodoma/comments/commentRss/37779.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dodoma/services/trackbacks/37779.html</trackback:ping><description><![CDATA[
		<p>摘选自 Matrix</p>
		<p>作者：Matrix成员：jdbc</p>
		<p> </p>
		<p>近期到CSDN论坛看看一些网友贴的面试题，其中关于String的问题常常被提及。我一直以为自己很清楚这个东西了，其实深究起来，发现自己并不那么清楚，会犯一些错误；同时也产生了一些联想。小结一下。<br /><br />1、"abc"与new String("abc");<br />    经常会问到的面试题：String s = new String("abc");创建了几个String Object?【如这里创建了多少对象? 和一道小小的面试题 】<br /><br />    这个问题比较简单，涉及的知识点包括：<br /><br />引用变量与对象的区别； <br />字符串文字"abc"是一个String对象； <br />文字池[pool of literal strings]和堆[heap]中的字符串对象。<br />    一、引用变量与对象：除了一些早期的Java书籍和现在的垃圾书籍，人们都可以从中比较清楚地学习到两者的区别。A aa;语句声明一个类A的引用变量aa[我常常称之为句柄]，而对象一般通过new创建。所以题目中s仅仅是一个引用变量，它不是对象。[ref 句柄、引用与对象]<br /><br />    二、Java中所有的字符串文字[字符串常量]都是一个String的对象。有人[特别是C程序员]在一些场合喜欢把字符串"当作/看成"字符数组，这也没有办法，因为字符串与字符数组存在一些内在的联系。事实上，它与字符数组是两种完全不同的对象。<br /><br />        System.out.println("Hello".length());<br />        char[] cc={'H','i'};<br />        System.out.println(cc.length);<br /><br />    三、字符串对象的创建:由于字符串对象的大量使用[它是一个对象，一般而言对象总是在heap分配内存]，Java中为了节省内存空间和运行时间[如比较字符串时，==比equals()快]，在编译阶段就把所有的字符串文字放到一个文字池[pool of literal strings]中，而运行时文字池成为常量池的一部分。文字池的好处，就是该池中所有相同的字符串常量被合并，只占用一个空间。我们知道，对两个引用变量，使用==判断它们的值[引用]是否相等，即指向同一个对象：<br /><br /></p>
		<pre class="overflow">String s1 = "abc" ;<br />String s2 = "abc" ;<br />if( s1 == s2 ) <br />    System.out.println("s1,s2 refer to the same object");<br />else     System.out.println("trouble");</pre>
		<br />
		<br />    这里的输出显示，两个字符串文字保存为一个对象。就是说，上面的代码只在pool中创建了一个String对象。<br /><br />    现在看String s = new String("abc");语句，这里"abc"本身就是pool中的一个对象，而在运行时执行new String()时，将pool中的对象复制一份放到heap中，并且把heap中的这个对象的引用交给s持有。ok，这条语句就创建了2个String对象。<br /><br /><pre class="overflow">String s1 = new String("abc") ;<br />String s2 = new String("abc") ;<br />if( s1 == s2 ){ //不会执行的语句}</pre><br /><br />    这时用==判断就可知，虽然两个对象的"内容"相同[equals()判断]，但两个引用变量所持有的引用不同，<br /><br />    BTW：上面的代码创建了几个String Object? [三个，pool中一个，heap中2个。]<br />    [Java2 认证考试学习指南 (第4版)( 英文版)p197-199有图解。]<br /><br /><br />2、字符串的+运算和字符串转换<br />    字符串转换和串接是很基础的内容，因此我以为这个问题简直就是送分题。事实上，我自己就答错了。<br /><br />String str = new String("jf"); // jf是接分<br />str = 1+2+str+3+4;<br />一共创建了多少String的对象？[我开始的答案：5个。jf、new、3jf、3jf3、3jf34]<br /><br />    首先看JLS的有关论述：<br /><br />    一、字符串转换的环境[JLS 5.4 String Conversion]<br /><br />    字符串转换环境仅仅指使用双元的+运算符的情况，其中一个操作数是一个String对象。在这一特定情形下，另一操作数转换成String，表达式的结果是这两个String的串接。<br /><br />    二、串接运算符[JLS 15.18.1 String Concatenation Operator + ]<br /><br />    如果一个操作数/表达式是String类型，则另一个操作数在运行时转换成一个String对象，并两者串接。此时，任何类型都可以转换成String。[这里，我漏掉了"3"和"4"]<br /><br />如果是基本数据类型，则如同首先转换成其包装类对象，如int x视为转换成Integer(x)。 <br />现在就全部统一到引用类型向String的转换了。这种转换如同[as if]调用该对象的无参数toString方法。[如果是null则转换成"null"]。因为toString方法在Object中定义，故所有的类都有该方法，而且Boolean, Character, Integer, Long, Float, Double, and String改写了该方法。 <br />关于+是串接还是加法，由操作数决定。1+2+str+3+4 就很容易知道是"3jf34"。[BTW :在JLS的15.18.1.3中举的一个jocular little example，真的很无趣。]<br />    下面的例子测试了改写toString方法的情况.。<br /><br /><pre class="overflow">class A{<br />    int i = 10;<br />    public static void main(String []args){<br />        String str = new String("jf");<br />        str += new A();<br />        System.out.print(str);<br />    }<br /><br />    public String toString(){<br />        return " a.i ="+i+"\n";<br />    }<br />}</pre><br /><br />三、字符串转换的优化<br /><br />按照上述说法，str = 1+2+str+3+4;语句似乎应该就应该生成5个String对象：<br /><br />1+2 ＝3，then 3→Integer(3)→"3" in pool? [假设如此] <br />"3"+str(in heap) = "3jf"     (in heap) <br />"3jf" +3 ,first 3→Integer(3)→"3" in pool? [则不创建] then "3jf3" <br />"3jf3"+4 create "4"  in pool <br />then "3jf34"<br /><br />    这里我并不清楚3、4转换成字符串后是否在池中，所以上述结果仍然是猜测。<br /><br />    为了减少创建中间过渡性的字符串对象，提高反复进行串接运算时的性能，a Java compiler可以使用StringBuffer或者类似的技术，或者把转换与串接合并成一步。例如：对于 a + b + c ，Java编译器就可以将它视为[as if]<br /><br />    new StringBuffer().append(a).append(b).append(c).toString();<br /><br />    注意，对于基本类型和引用类型，在append(a)过程中仍然要先将参数转换，从这个观点看，str = 1+2+str+3+4;创建的字符串可能是"3"、"4"和"3jf34"[以及一个StringBuffer对象]。<br /><br />    现在我仍然不知道怎么回答str = 1+2+str+3+4;创建了多少String的对象，。或许，这个问题不需要过于研究，至少SCJP不会考它。<br /><br />3、这又不同：str = "3"+"jf"+"3"+"4";<br />    如果是一个完全由字符串文字组成的表达式，则在编译时，已经被优化而不会在运行时创建中间字符串。测试代码如下：<br /><br /><pre class="overflow">String str1 ="3jf34";<br />        String str2 ="3"+"jf"+"3"+"4"; <br />        if(str1 == str2) {<br />            System.out.println("str1 == str2");<br />        }else {<br />            System.out.println("think again");<br />        }<br />        if(str2.equals(str1))<br />            System.out.println("yet str2.equals(str1)");</pre><br /><br />    可见，str1与str2指向同一个对象，这个对象在pool中。所有遵循Java Language Spec的编译器都必须在编译时对constant expressions 进行简化。JLS规定：Strings computed by constant expressions (&amp;yacute;15.28) are computed at compile time and then treated as if they were literals. <br /><br />    对于String str2 ="3"+"jf"+"3"+"4";我们说仅仅创建一个对象。注意，“创建多少对象”的讨论是说运行时创建多少对象。<br /><br />    BTW：编译时优化<br /><br /><pre class="overflow">    String x = "aaa " + "bbb ";<br />    if (false) {<br />        x = x + "ccc ";<br />    }<br />    x +=  "ddd ";<br /><br />    等价于：<br /><br />    String x = "aaa bbb ";<br />    x = x + "ddd ";</pre><br /><br />4、不变类<br />    String对象是不可改变的(immutable)。有人对str = 1+2+str+3+4;语句提出疑问,怎么str的内容可以改变？其实仍然是因为不清楚：引用变量与对象的区别。str仅仅是引用变量，它的值——它持有的引用可以改变。你不停地创建新对象，我就不断地改变指向。[参考TIJ的Read-only classes。]<br /><br />    不变类的关键是，对于对象的所有操作都不可能改变原来的对象[只要需要，就返回一个改变了的新对象]。这就保证了对象不可改变。为什么要将一个类设计成不变类？有一个OOD设计的原则：Law of Demeter。其广义解读是：<br /><br />    使用不变类。只要有可能，类应当设计为不变类。<br /><img src ="http://www.blogjava.net/dodoma/aggbug/37779.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dodoma/" target="_blank">dodoma</a> 2006-03-28 13:19 <a href="http://www.blogjava.net/dodoma/articles/37779.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>