黑马程序员技术交流社区

标题: String主要特点归纳 [打印本页]

作者: 黄成超    时间: 2013-2-8 10:28
标题: String主要特点归纳
本帖最后由 黄成超 于 2013-2-8 10:30 编辑

String主要特点归纳:
(1)不可变String
  String对象是不可变的,每一次修改String的值,都会创建一个全新的String,以包含修改后的内容,比如:
  1. public class Test1 {
  2. public static void main(String[] args) {

  3. String q = "howdy";
  4. System.out.println(q);//howdy
  5. String qq = upcase(q);
  6. System.out.println(qq);//HOWDY,也许这里的返回值不能说明q是否改变,因为返回值确实也可以先创建一个对象,用于保存临时String对象
  7. System.out.println(q);//howdy,但是通过打印q的值,就你能了解到q的值确实并未改变
  8. }
  9. /**
  10. * 写一个自定义的upcase方法,用于返回s转化为大写的结果
  11. *
  12. */
  13. public static String upcase(String s)
  14. {
  15. System.out.println(s.hashCode());
  16. return s.toUpperCase();
  17. }
复制代码
关于字符串的不可改变,jdk开发文档也有说明,同时因为String对象不可改变,所以可以共享,如:
String str = "abc";
等效于:
char[] data = {'a','b','c'};
String str = new String(data);
需要强调的是,字符串是常量,他们的值在创建之后不可变(这个jdk开发文档有说明),并不是说创建多个String对象,内存中只有一个,
  不可改变,指的是原来的String的值不能改变。
  因此:
   String str1 = new String("abc");
   String str2 = new String("abc");
   System.out.println(str1==str2); //false
  结果显然是false。
  
  而字符串是常量,所以
  String str3 = "abc";
  String str4 = "abc";
  System.out.println(str3==str4);//true
  常量存放在常量池中,两个"abc"存放位置是相同的。这点要区别。

(2)String、StringBuffer、StringBuilder比较
  String是java中的常用字符串对象,而StringBuffer,StringBuilder则是类似于String的字符串缓冲区。
  String对象创建后不能修改,上面已有说明;
  StringBuffer不能直接修改,但可以通过某些方法改变内容与长度,可安全的用于多线程
  StringBuilder为可变字符序列,StringBuilder则用于多线程不安全,但相对更高效,所以除非在多线程,否则建议使用StringBuilder
  StringBuffer,
   (关于String,StringBuffer,StringBuilder以及类似单个类或对象方法的比较,建议查看jdk开发文档!)

(3)String的"+"、"+="
  原来一直不是很清楚下面的到底创建了多少对象:
  String s = "abc" + "addf" +"def" +47;
  相信看完下面这个例题分析,了解String的底层创建过程,就能够清楚知道:
  1. class StringTest
  2. {
  3. public static void main(String[] args)
  4. {
  5. String mango = "mango";
  6. String s = "abc" + mango +"def" +47;
  7. System.out.println(s);
  8. }
  9. }
复制代码
这段代码是怎么工作的呢?通过jdk自带的工具javap反编译这段代码,如下:
  javap -c -StringTest
  注意,反编译前一定要先编译哦!

  通过反编译的图片可以知道,在运行的过程中编译器创建了一个StringBuilder对象,用以构造最终的String(使用StringBuilder,是因为StringBuilder更高效),并
  为每个字符串调用一次append()方法,首先是将"abc"通过append方法放在StringBuilder中,然后使用append()用于包含"abc"与mango连接后的字符串
  ,然后再次调用append()方法,把def加入StringBuilder中,以此类推,总共4次。最后用toString方法,生成结果String对象(这个在jdk中也有说明)。

对于一些容易产生误解的知识点,可能还不够完整,希望大家都补充一下。。。。
                                                
                                          参考《java编程思想》及jdk1.6开发文档以及自己总结及代码验证




作者: 刘凯    时间: 2013-2-8 11:18
受教  顶一个
作者: 王昕    时间: 2013-2-8 14:26
常量池是栈还是堆呢?
作者: 黄成超    时间: 2013-2-8 15:46
王昕 发表于 2013-2-8 14:26
常量池是栈还是堆呢?

常量池在java用于保存在编译期已确定的,已编译的class文件中的一份数据。它包括了关于类,方法,接口等中的常量,也包括字符串常量,如String s = "java"这种申明方式;当然也可扩充,执行器产生的常量也会放入常量池,故认为常量池是JVM的一块特殊的内存空间。关于常量池,比较复杂,有兴趣是话,可以自己了解一下。
作者: pzfpang449    时间: 2013-2-8 17:18
看了楼主的总结,我也加上一些关于String其他的内容
1. 首先String不属于8种基本数据类型,String是一个对象。

因为对象的默认值是null,所以String的默认值也是null;但它又是一种特殊的对象,有其它对象没有的一些特性。

2. new String()和new String(“”)都是申明一个新的空字符串,是空串不是null;

3. String str=”kvill”;

String str=new String (“kvill”);的区别:

Ps:  
在这里,我们不谈堆,也不谈栈,只先简单引入常量池这个简单的概念。

  常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。

看例1:

String s0=”kvill”;

String s1=”kvill”;

String s2=”kv” + “ill”;

System.out.println( s0==s1 );

System.out.println( s0==s2 );
结果为:

true

true


首先,我们要知结果为道Java会确保一个字符串常量只有一个拷贝。

  因为例子中的s0和s1中的”kvill”都是字符串常量,它们在编译期就被确定了,所以s0==s1为true;而”kv”和”ill”也都是字符串常量,
当一个字符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,所以s2也同样在编译期就被解析为一个字符串常量,
所以s2也是常量池中”kvill”的一个引用。

所以我们得出s0==s1==s2;

  用new String() 创建的字符串不是常量,不能在编译期就确定,所以new String() 创建的字符串不放入常量池中,它们有自己的地址空间。

看例2:

String s0=”kvill”;

String s1=new String(”kvill”);

String s2=”kv” + new String(“ill”);

System.out.println( s0==s1 );

System.out.println( s0==s2 );

System.out.println( s1==s2 );
结果为:

false

false

false
  例2中s0还是常量池中”kvill”的应用,s1因为无法在编译期确定,所以是运行时创建的新对象”kvill”的引用,
s2因为有后半部分new String(“ill”)所以也无法在编译期确定,所以也是一个新创建对象”kvill”的应用;明白了这些也就知道为何得出此结果了。

希望对楼主有所帮助
作者: 黄玉昆    时间: 2013-2-8 19:02
不错的总结,我也会好好总结总结关于String这个特殊的类型的。
作者: 朱玉玺    时间: 2013-2-16 12:53
王昕 发表于 2013-2-8 14:26
常量池是栈还是堆呢?

每个类都用自己的常量池,并且存在于方法区中;而方法区呢,根据jvm规范中说是堆的逻辑分区,只不过垃圾回收期不对它进行管理~




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2