java String类的一点总结

1.重要特征:
        
          String 字符串常量---》是不可改变的量,在字符串不经常变化的场景中可以使用 String 类,例如常量的声明、少量的变量运算。
         
          StringBuffer 字符串变量(线程安全)---》运行在多线程环境,且频繁进行字符串运算(如拼接、替换、删除等),则可以考虑使用 StringBuffer,
                                                   例如 XML 解析、HTTP 参数解析和封装。
         
          StringBuilder 字符串变量(非线程安全)---》运行在单线程的环境中,且频繁进行字符串运算(如拼接、替换、和删除等),则可以考虑使用 StringBuilder,
                                                     如 SQL 语句的拼装、JSON 封装等。
   1.2创建字符串的三种方式:
            使用new关键字创建字符串,比如String s1 = new String("abc");

            直接指定。比如String s2 = "abc";-----》使用直接指定或者使用纯字符串串联来创建String对象,则仅仅会检查维护String池中的字符串,
                                                   池中没有就在池中创建一个,有则罢了!但绝不会在堆栈区再去创建该String对象。

            使用串联生成新的字符串。比如String s3 = "ab" + "c";

      原理1:当使用任何方式来创建一个字符串对象s=X时,Java运行时(运行中JVM)会拿着这个X在String池中找是否存在内容相同的字符串对象,如果不存在,则在池中创建一个字符串s,否则,不在池中添加。
 
      原理2:Java中,只要使用new关键字来创建对象,则一定会(在堆区或栈区)创建一个新的对象。
 
      原理3:使用直接指定或者使用纯字符串串联来创建String对象,则仅仅会检查维护String池中的字符串,池中没有就在池中创建一个,有则罢了!但绝不会在堆栈区再去创建该String对象。
 
      原理4:使用包含变量的表达式来创建String对象,则不仅会检查维护String池,而且还会在堆栈区创建一个String对象。


2.String特性【不能被继承】:

           String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法
         
           String类其实是通过【本质】char数组来保存字符串的【实现了charsequence接口】
 
           对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象【如concat sub replace】
   
    2.2JVM常量池:
           常量池中的数据是那些在编译期间被确定,并被保存在已编译的.class文件中的一些数据。除了包含所有的8种基本数据类型
          (char、byte、short、int、long、float、double、boolean)外,还有String及其数组的常量值,另外还有一些以文本形式出现的符号引用。

    2.3java栈【数据共享】:
            栈的特点是存取速度快(比堆块),但是空间小,数据生命周期固定,只能生存到方法结束。

            【例子】:如boolean b = true、char c = ‘c’、String str = “123”
                      true、c、123,这些等号右边的指的是编译期间可以被确定的内容,都被维护在常量池中
                      b、c、str这些等号左边第一个出现的指的是一个引用,引用的内容是等号右边数据在常量池中的地址
                      boolean、char、String这些是引用的类型
             
       2.4String【intern()】及其他基本数据类型也都是一样的:先看常量池中有没有要创建的数据,有就返回数据的地址,没有就创建一个。

       2.5String += “hello”或者字符串连接符 +
                               【会生成多个builder对象】 编译器每次碰到”+”的时候,会new一个StringBuilder出来,接着调用append方法,在调用toString方法,生成新字符串。
                                         
                                ---》会自动被JVM优化成:StringBuilder str = new StringBuilder(string);----》多个”+“将会创建很多的StringBuilder对象
                                                        str.append(“hello”);
                                                        str.toString();

         2.6String的concat()--》
                                通过两次字符串的拷贝,产生一个新的字符数组buf[],再根据字符数组buf[],new一个新的String对象出来
                                concat方法调用N次,将发生N*2次数组拷贝以及new出N个String对象,无论对于时间还是空间都是一种浪费。
        
    2.7String重写了equals()----》==比较的是引用类型变量的地址,基本类型变量的值
                                  equals()比较的不在是地址而是值


3.StringBuffer特性【线程安全】:
            StringBuffer和StringBuilder原理一样,无非是在底层维护了一个char数组,每次append的时候就往char数组里面放字符而已,在最终sb.toString()的时候,
            用一个new String()方法把char数组里面的内容都转成String。整个过程就new了一个StringBuilder对象一个String对象

        3.1同StringBuilder,在append()追加,将只会创建一次对象,在原来的基础上追加

        3.2都用在频繁进行字符串运算的环境中

        3.3对于间接相加(即包含字符串引用),形如s1+s2+s3; 效率要比直接相( String str = "111" + "222" + "333")加低,因为在编译器不会对引用变量进行优化。
            编译时优化:
            【例】String a = “hello2″;   String b = “hello” + 2; ------》  a==b在编译期间被优化为hello2,故运行期间指向相同的常量池地址
                  String a = “hello2″;    String b = “hello”;       String c = b + 2;----》!a==c存在引用,未能在编译期优化,生成的对象保存在堆上,地址不一致
                  String a = “hello2″;    final String b = “hello”; String c = b + 2;-----》a==c final定义,b在编译期直接被真实值替换,地址同
                  String a = "hello2";      final String b = getHello();  String c = b + 2;-----》赋值通过方法调用返回,b的值在运行期间才能知道,故地址不一致
    
               String str1 = "I"; str1 += "love"+"java";(1)    str1 = str1+"love"+"java";(2)(1会进行优化,而2不会,故1的效率高)
                

4.StringBuilder特性【线程不安全】:

      
       4.1StringBuilder唯一的性能损耗点在于char数组不够的时候需要进行扩容,扩容需要进行数组拷贝,一定程度上降低了效率。
          优化:如果可以估计到要拼接的字符串的长度的话,尽量利用构造函数指定他们的长度。


5.String str = new String(“abc”)创建了多少个对象
 
       5.1代码在运行期间确实只创建了一个对象,即在堆上创建了”abc”对象

       5.2运行时常量池中创建了一个”abc”对象,而在代码执行过程中确实只创建了一个String对象。

       5.3涉及到2个String对象

6.toString()   每个java类都会从Object类继承toString()方法。如:println()编译器会自动添加toString(),不用手动显示添加

7.null与“”的区别

         13.1String s="";【分配了一个内存空间,存了一个字符串对象】
                声明了一个对象实例,这个引用已经指向了一块是空字符串的内存空间,是一个实际的东西了,所以你可以对它进行任何操作

         13.2String a=null;【null是未分配堆内存空间,引用未指向任何内存空间】
                声明了一个空对象,对空对象做任何操作都不行的(报NullPointException),除了=和== 

         13.3String b;【声明一个字符串对象,但并没有分配内存】
                在成员变量的定义中,String s;等同于String s=null;-----》初始化为null

                而在本地变量(方法变量)的定义中,String s;不等同于String s=null;,这时要使用s必须显式地赋值【否则报异常】。
               
                在方法中定义变量都要显示赋初值,main()方法也不例外,而在方法之外编译器会自动赋初值。

    解决空字符串问题:
             对于字符串空值的判定,建议使用 apache-commons-lang  http://commons.apache.org/lang/api-2.5/org/apache/commons/lang/StringUtils.html

             有 isBlank/isNotBlank【包含“ ”】 和 isEmpty/isNotEmpty【不包含“ ”做非空处理】 方法【对于null “”的判定相同】

猜你喜欢

转载自yangzhe0609.iteye.com/blog/2396311