深入Java核心 Java内存分配原理精讲---3_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > 深入Java核心 Java内存分配原理精讲---3

深入Java核心 Java内存分配原理精讲---3

 2011/1/10 9:46:34  buliedian  http://buliedian.javaeye.com  我要评论(0)
  • 摘要:String常量池问题的几个例子下面是几个常见例子的比较分析和理解:Stringa="a1";Stringb="a"+1;System.out.println((a==b));//result=trueStringa="atrue";Stringb="a"+"true";System.out.println((a==b));//result=trueStringa="a3.4";Stringb="a"+3.4;System.out.println((a==b));//result=true分析
  • 标签:Java 内存分配

String常量池问题的几个例子

  下面是几个常见例子的比较分析和理解

  1. String?a?=?"a1" ;? ?
  2. String?b?=?"a" ?+?1 ;? ?
  3. System.out.println((a?==?b));?//result?=?true ?
  4. String?a?=?"atrue" ;? ?
  5. String?b?=?"a" ?+?"true" ;? ?
  6. System.out.println((a?==?b));?//result?=?true ?
  7. String?a?=?"a3.4" ;? ?
  8. String?b?=?"a" ?+?3.4 ;? ?
  9. System.out.println((a?==?b));?//result?=?true ?

  分析:JVM对于字符串常量的"+"号连接,将程序编译期,JVM就将常量字符串的"+"连接优化为连接后的值,拿"a" + 1来说,经编译器优化后在class中就已经是a1。在编译期其字符串常量的值就确定下来,故上面程序最终的结果都为true。

  1. String?a?=?"ab" ;? ?
  2. String?bb?=?"b" ;? ?
  3. String?b?=?"a" ?+?bb;? ?
  4. System.out.println((a?==?b));?//result?=?false ?

  分析:JVM对于字符串引用,由于在字符串的"+"连接中,有字符串引用存在,而引用的值在程序编译期是无法确定的,即"a" + bb无法被编译器优化,只有在程序运行期来动态分配并将连接后的新地址赋给b。所以上面程序的结果也就为false。

  1. String?a?=?"ab" ;? ?
  2. final ?String?bb?=?"b" ;? ?
  3. String?b?=?"a" ?+?bb;? ?
  4. System.out.println((a?==?b));?//result?=?true ?

  分析:和[3]中唯一不同的是bb字符串加了final修饰,对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的 常量 池中或嵌入到它的字节码流中。所以此时的"a" + bb和"a" + "b"效果是一样的。故上面程序的结果为true。

  1. String?a?=?"ab" ;? ?
  2. final ?String?bb?=?getBB();? ?
  3. String?b?=?"a" ?+?bb;? ?
  4. System.out.println((a?==?b));?//result?=?false? ?
  5. private ?static ?String?getBB()?{ ?
  6. return ?"b" ;? ?
  7. }?

  分析:JVM对于字符串引用bb,它的值在编译期无法确定,只有在程序运行期调用方法后,将方法的返回值和"a"来动态连接并分配地址为b,故上面 程序的结果为false。

  通过上面4个例子可以得出得知:

  String? s? =? "a" + "b" + "c";?
  就等价于String s = "abc";??
  String? a? =? "a";??
  String? b? =? "b";??
  String? c? =? "c";??
  String? s? =?? a? +? b? +? c;?

  这个就不一样了,最终结果等于:

  1. StringBuffer?temp?=?new ?StringBuffer();??? ?
  2. temp.append(a).append(b).append(c);??? ?
  3. String?s?=?temp.toString();?

  由上面的分析结果,可就不难推断出String 采用连接运算符(+)效率低下原因分析,形如这样的代码:

  1. public ?class ?Test?{ ?
  2. public ?static ?void ?main(String?args[])?{ ?
  3. String?s?=?null ; ?
  4. for (int ?i?=?0 ;?i?<?100 ;?i++)?{ ?
  5. s?+=?"a" ; ?
  6. } ?
  7. } ?
  8. }?

  每做一次 + 就产生个StringBuilder对象,然后append后就扔掉。下次循环再到达时重新产生个StringBuilder对象,然后 append 字符串,如此循环直至结束。如果我们直接采用 StringBuilder 对象进行 append 的话,我们可以节省 N - 1 次创建和销毁对象的时间。所以对于在循环中要进行字符串连接的应用,一般都是用StringBuffer或StringBulider对象来进行 append操作。

  String对象的intern方法理解和分析:

  1. public ?class ?Test4?{ ?
  2. private ?static ?String?a?=?"ab" ;? ?
  3. public ?static ?void ?main(String[]?args){ ?
  4. String?s1?=?"a" ; ?
  5. String?s2?=?"b" ; ?
  6. String?s?=?s1?+?s2; ?
  7. System.out.println(s?==?a);//false ?
  8. System.out.println(s.intern()?==?a);//true?? ?
  9. } ?
  10. }?

  这里用到JAVA 里面是一个常量池的问题。对于 s1+s2操作,其实是在堆里面重新创建了一个新的对象,s保存的是这个新对象在堆空间的的内容,所 以s与a的值是不相等的。而当调用s.intern()方法,却可以返回s在常量池中的地址值,因为a的值存储在常量池中,故s.intern和a的值相 等。

  总结

  栈中用来存放一些原始数据类型的局部变量数据和对象的引用(String,数组.对象等等)但不存放对象内容

  堆中存放使用new关键字创建的对象.

  字符串是一个特殊包装类,其引用是存放在栈里的,而对象内容必须根据创建方式不同定(常量池和堆).有的是编译期就已经创建好,存放在字符串常 量池中,而有的是运行时才被创建.使用new关键字,存放在堆中。

发表评论
用户名: 匿名