String类

String类构造方法的部分源码

package java.lang;

import java.io.ObjectStreamField;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Formatter;
import java.util.Locale;
import java.util.Objects;
import java.util.StringJoiner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

/**
 * {@code String} 类表示字符串。所有java程序中的字符串,如{@code "abc"},是作为该类的实例实现。
 * <p>字符串是常量,它们的值在它们之后不能改变。创建。字符串缓冲区支持可变字符串。因为字符串对象是不可变的,所以它们可以被共享。例如:
 * <blockquote><pre>
 *     String str = "abc";
 * </pre></blockquote><p>
 * 相当于:
 * <blockquote><pre>
 *     char data[] = {'a', 'b', 'c'};
 *     String str = new String(data);
 * </pre></blockquote><p>
 * 下面是一些字符串如何使用的例子:
 * <blockquote><pre>
 *     System.out.println("abc");
 *     String cde = "cde";
 *     System.out.println("abc" + cde);
 *     String c = "abc".substring(2,3);
 *     String d = cde.substring(1, 2);
 * </pre></blockquote>
 * <p>
 * String 类包括的方法可用于检查序列的单个字符、比较字符串、搜索字符串、提取子字符串、创建字符串副本并将所有字符全部转换为大写或小写。
 * 大小写映射基于 Character 类指定的 Unicode 标准版。 
 * <p>
 * Java 语言提供对字符串串联符号("+")以及将其他对象转换为字符串的特殊支持。字符串串联是通过 StringBuilder(或 StringBuffer)类及其 append 方法实现的。
 * 字符串转换是通过 toString 方法实现的,该方法由 Object 类定义,并可被 Java 中的所有类继承。有关字符串串联和转换的更多信息,请参阅 Gosling、Joy和
 * Steele合著的 The Java Language Specification。 
 * <i>java语言规范</i>.
 *
 * <p> 除非另行说明,否则将 null 参数传递给此类中的构造方法或方法将抛出 NullPointerException。 
 *
 * <p>String 表示一个 UTF-16 格式的字符串,其中的增补字符 由代理项对 表示(有关详细信息,请参阅 Character 类中的 Unicode 字符表示形式)。
 * 索引值是指 char 代码单元,因此增补字符在 String 中占用两个位置。 
 * <p>String 类提供处理 Unicode 代码点(即字符)和 Unicode 代码单元(即 char 值)的方法。 
 *
 * @author  Lee Boynton
 * @author  Arthur van Hoff
 * @author  Martin Buchholz
 * @author  Ulf Zibis
 * @see     java.lang.Object#toString()
 * @see     java.lang.StringBuffer
 * @see     java.lang.StringBuilder
 * @see     java.nio.charset.Charset
 * @since   JDK1.0
 */

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** 该值用于字符存储。 */
    private final char value[];

    /** 字符串缓存的哈希代码 */
    private int hash; // Default to 0
  
    private static final long serialVersionUID = -6849794470754667710L;
    
    private static final ObjectStreamField[] serialPersistentFields =
        new ObjectStreamField[0];
    
    /**
     * 初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。由于 String 是不可变的,
     * 所以无需使用此构造方法,除非需要 original 的显式副本。 
     *
     * @param  original 一个 String。 
     */
    public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }

    /**
     * 分配一个新的 String,使其表示字符数组参数中当前包含的字符序列。该字符数组的内容已被复制;后续对字符数组的修改不会影响新创建的字符串。 
     * @param  value 字符串的初始值 
     */
    public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }

    /**
     * 分配一个新的 String,它包含取自字符数组参数一个子数组的字符。 offset 参数是子数组第一个字符的索引, count 参数指定子数组的长度。该子数组的内容已
     * 被复制;后续对字符数组的修改不会影响新创建的字符串。 
     *
     * @param  value 作为字符源的数组。
     *
     * @param  offset 初始偏移量。
     *
     * @param  count 长度。 
     *
     * @throws  IndexOutOfBoundsException  如果 offset 和 count 参数索引字符超出 value 数组的范围。 
     */
    public String(char value[], int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count <= 0) {
            if (count < 0) {
                throw new StringIndexOutOfBoundsException(count);
            }
            if (offset <= value.length) {
                this.value = "".value;
                return;
            }
        }
        // offset 或 count 也许  -1>>>1.
        if (offset > value.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }
    
    private static void checkBounds(byte[] bytes, int offset, int length) {
        if (length < 0)
            throw new StringIndexOutOfBoundsException(length);
        if (offset < 0)
            throw new StringIndexOutOfBoundsException(offset);
        if (offset > bytes.length - length)
            throw new StringIndexOutOfBoundsException(offset + length);
    }

    /**
     * 通过使用指定的字符集解码指定的 byte 子数组,构造一个新的 String。新 String 的长度是一个字符集函数,因此可能不等于子数组的长度。
     *  
     *
     * <p> 当给定 byte 在给定字符集中无效的情况下,此构造方法的行为没有指定。如果需要对解码过程进行更多控制,则应该使用 CharsetDecoder 类。
     *
     * @param  bytes 要解码为字符的 byte 
     *
     * @param  offset 要解码的第一个 byte 的索引 
     *
     * @param  length 要解码的 byte 数 

     * @param  charsetName 受支持 charset 的名称 
     *
     * @throws  如果指定的字符集不受支持 
     *
     * @throws  IndexOutOfBoundsException 如果 offset 和 length 参数索引字符超出 bytes 数组的范围 
     *
     * @since  JDK1.1
     */
    public String(byte bytes[], int offset, int length, String charsetName)
            throws UnsupportedEncodingException {
        if (charsetName == null)
            throw new NullPointerException("charsetName");
        checkBounds(bytes, offset, length);
        this.value = StringCoding.decode(charsetName, bytes, offset, length);
    }

    /**
     * 通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String。新 String 的长度是字符集的函数,因此可能不等于 byte 数组的长度。 
     *
     * <p>当给定 byte 在给定字符集中无效的情况下,此构造方法的行为没有指定。如果需要对解码过程进行更多控制,则应该使用 CharsetDecoder 类。
     *
     * @param  bytes 要解码为字符的 byte 
     *
     * @param  charsetName 受支持的 charset 的名称 
     *
     * @throws  UnsupportedEncodingException 如果指定字符集不受支持 
     *
     * @since  JDK1.1
     */
    public String(byte bytes[], String charsetName)
            throws UnsupportedEncodingException {
        this(bytes, 0, bytes.length, charsetName);
    }
    /**
     *  通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。新 String 的长度是字符集的函数,因此可能不等于该子数组的长度。 
     *
     * <p>当给定 byte 在给定字符集中无效的情况下,此构造方法的行为没有指定。如果需要对解码过程进行更多控制,则应该使用 CharsetDecoder 类。 
     *
     * @param  bytes 要解码为字符的 byte 
     *
     * @param  offset  要解码的第一个 byte 的索引 
     *
     * @param  length  要解码的 byte 数 
     *
     * @throws  IndexOutOfBoundsException 如果 offset 和 length 参数索引字符超出 bytes 数组的范围 
     *
     * @since  JDK1.1
     */
    public String(byte bytes[], int offset, int length) {
        checkBounds(bytes, offset, length);
        this.value = StringCoding.decode(bytes, offset, length);
    }

    /**
     * 通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。新 String 的长度是字符集的函数,因此可能不等于 byte 数组的长度。 
     *
     * <p> 当给定 byte 在给定字符集中无效的情况下,此构造方法的行为没有指定。如果需要对解码过程进行更多控制,则应该使用 CharsetDecoder 类。 
     *
     * @param  bytes 要解码为字符的 byte 
     *
     * @since  JDK1.1
     */
    public String(byte bytes[]) {
        this(bytes, 0, bytes.length);
    }

    /**
     * 分配一个新的字符串,它包含字符串缓冲区参数中当前包含的字符序列。该字符串缓冲区的内容已被复制,后续对它的修改不会影响新创建的字符串。 
     *
     * @param  buffer 一个 StringBuffer
     */
    public String(StringBuffer buffer) {
        synchronized(buffer) {
            this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
        }
    }

    /**
     * 分配一个新的字符串,它包含字符串生成器参数中当前包含的字符序列。该字符串生成器的内容已被复制,后续对它的修改不会影响新创建的字符串。 
     *
     * <p>提供此构造方法是为了简化到 StringBuilder 的迁移。通过 toString 方法从字符串生成器中获取字符串可能运行的更快,因此通常作为首选。 
     *
     * @param   builder  一个 StringBuilder
     *
     * @since  1.5
     */
    public String(StringBuilder builder) {
        this.value = Arrays.copyOf(builder.getValue(), builder.length());
    }
}

源码理解

String类位于java.lang包下实现了Comparable和Serializable接口,因此可以序列化,可以进行比较,并且String类是被final修饰,因此不能被继承,并且该类中的成员默认final方法。String类中包含一个不可变的char数组用来存放字符串,一个int型的变量hash用来存放计算后的哈希值,因此String类本质是char数组。使用 byte[] 构造 String时可以指定解码使用的字符集,默认是ISO-8859-1 编码格式进行编码操作。

字符集测试案例

package ecut.strings;

import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 *  Java支持的字符集。
 *  常用字符编码:
 *  UTF-8 ( Unicode 的子集 )
 *  GBK ( GB2312 / GB18030 ) 中国大陆采用的简体汉字编码 
 *  Big5 繁体中文 (正体中文)
 *  ISO-8859-1
 */
public class CharsetTest {

    public static void main(String[] args) {
        //构造从规范 charset 名称到 charset 对象的有序映射。
        Map<String,Charset> map = Charset.availableCharsets();
        
        // 迭代 map 返回此映射中包含的键的 Set 视图。
        Set<String> keys = map.keySet();
        
        // foreach 循环中 可以处理的 对象有 数组 或 java.lang.Iterable 接口的实现类
        for( String key : keys ) {
            //返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。
            Charset value = map.get( key );
            System.out.println( key + " : " + value );
        }
        
        //返回在此 set 中的元素上进行迭代的迭代器。
        Iterator<String> it =  keys.iterator();
        
        while( it.hasNext() ) {
            String key = it.next();
            Charset value = map.get( key ); // 根据 key 取出 value
            System.out.println( key + " : " + value );
        } 

    }

}

运行结果如下:

Big5 : Big5
Big5-HKSCS : Big5-HKSCS
CESU-8 : CESU-8
......
x-windows-949 : x-windows-949 x-windows-950 : x-windows-950 x-windows-iso2022jp : x-windows-iso2022jp

String类创建方式

1、双引号型

2、new型

package ecut.strings;

public class StringTest1 {

    public static void main(String[] args) {
        
        // 所有的 "" 包起来的 字符串 字面值一律放在 字符串常量池中
        //去字符串常量池池寻找相同内容的字符串,如果存在就直接拿出来应用,如果不存在则创建一个新的字符串放在常量池中。
        String s = "hello,ecut" ;
        System.out.println( System.identityHashCode( s ) );
        //通过 new关键字创建 String 对象,每次调用都会创建一个新的对象。
        String x = new String( "hello,ecut" );
        System.out.println( System.identityHashCode( x ) );
        
        System.out.println( s == x );
        
        // 返回字符串对象的规范化表示形式
        // 如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串。
        // 否则,将此 String 对象添加到池中,并返回此 String 对象的引用(加入到池中以后的那个串的地址)
        String str = x.intern();
        System.out.println( System.identityHashCode( str ) );
        
        System.out.println( str == s );
        
        
    }

}

运行结果如下:

366712642
1829164700
false
366712642
true

从结果可以看出s和x的地址是不相等的,是因为String s = "hello,ecut", 首先在常量池中查找是否存在内容为"hello,ecut"字符串对象,如果不存在则在常量池中创建"hello,ecut",并让s引用该对象(12345),如果存在则直接让s引用该对象,而new String( "hello,ecut" )时会在堆中创建一个对象ABCDE,并由栈中x引用堆中的ABCDE对象,然后在在字符串常量池中查看,是否存在内容为"hello,ecut"字符串对象,若存在,则将new出来的字符串对象与字符串常量池中的对象(12345)联系起来若不存在,则在字符串常量池中创建一个内容为"hello,ecut"的字符串对象,并将堆中的对象与之联系起来。x.intern()方法则是如果池已经包含一个等于此 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串,否则,将此 String 对象添加到池中,并返回此 String 对象的引用(加入到池中以后的那个串的地址)。因此str和s地址相同。

 ==比较的是2个对象的地址,而equals比较的是2个对象的内容。

package ecut.strings;

public class StringTest2 {

    public static void main(String[] args) {
        
        final char[] chars = { '春' , '眠' , '不' , '觉' , '晓' };
        System.out.println( "chars: " + System.identityHashCode( chars ) );
        
        String s = new String( chars );
        System.out.println( "s : " + System.identityHashCode( s ) );
        
        System.out.println( s );
        
        String x = s.intern(); // 返回规范化表示形式
        
        System.out.println( "s.intern : " + System.identityHashCode( x ) );
        
        System.out.println( s == x ); // true
        
        String r = "春眠不觉晓";
        System.out.println( s == r );
        
    }

}

运行结果如下:

chars: 366712642
s : 1829164700
春眠不觉晓
s.intern : 1829164700
true
true

从结果可以看出s和r的地址是相等的,r调用的是String类的无参构造函数,根据源码this.value = "".value;其中value定义private final char[]创建一个空串并将它的值放在数组value中,s调用的构造方法是使用字符数组的有参构造,根据源码this.value = Arrays.copyOf(value,value.length)是将传入的字符数组拷贝到数组value中。因此String r = "春眠不觉晓";和 final char[] chars = { '春' , '眠' , '不' , '觉' , '晓' }; String s = new String( chars );是等价的。

package ecut.strings;

public class StringTest3 {

    public static void main(String[] args) {
        
        String r = "春眠不觉晓";
        System.out.println( "r : " + System.identityHashCode( r ) );
        
        final char[] chars = { '春' , '眠' , '不' , '觉' , '晓' };
        
        String s = new String( chars );
        System.out.println( "s : " + System.identityHashCode( s ) );
        
        String x = s.intern(); 
        System.out.println( "x : " + System.identityHashCode( x ) );
        
    }

}

运行结果如下:

r : 366712642
s : 1829164700
x : 366712642

栈:运行时的单位,存放基本类型的变量数据和对象的引用,栈解决程序的运行问题,即程序如何执行,或者说如何处理数据。

堆:存储的单位,用于存放所以的JAVA对象,堆解决的是数据存储的问题,即数据怎么放、放在哪儿。

常量池:存放字符串常量和基本类型常量(public static final)

使用字节数组构造String测试案例:

package ecut.strings;

import java.util.Arrays;

//  对于中文来说 UTF-8 编码可以是 2~3 个字节 (大部分都是3个字节)
public class StringTest4 {

    public static void main(String[] args) throws Exception {
        
        String s = "今天天气孬abc" ;
        System.out.println( s.length() );
    
        // byte[] bytes = s.getBytes(); // 采用默认编码
        byte[] bytes = s.getBytes( "UTF-8" );
        
        System.out.println( Arrays.toString( bytes ) );
        System.out.println( bytes.length );
        
        // String x = new String( bytes );
        String x = new String( bytes , "UTF-8");
        System.out.println( x );
        
    }

}

运行结果如下:

8
[-28, -69, -118, -27, -92, -87, -27, -92, -87, -26, -80, -108, -27, -83, -84, 97, 98, 99]
18
今天天气孬abc

字符串联的方式

测试案例:

package ecut.strings;

/**
 * 当 字符串 变量 参与 串联 操作时
 * 是通过 StringBuilder ( 或 StringBuffer ) 类及其 append 方法实现的
 */
public class StringTest5 {

    public static void main(String[] args) {
        
        String a = "abc" ;
        String b = "xyz";
        
        String d = "abcxyz" ;
        // 两个字符串字面值 通过 + 串联,直接在 池中完成
        String c = "abc" + "xyz" ; // + 是 "串联" 作用

        System.out.println( c == d );
        
        System.out.println( "~~~~~~~~~~~~~~" );
        
        // 字符串串联是通过 StringBuilder ( 或 StringBuffer ) 类及其 append 方法实现的
        // 1、StringBuilder sb = new StringBuilder( a );
        // 2、sb.append( b ) ;
        // 3、sb.toString() ---> new String( chars )
        String e = a + b ;
        System.out.println( e == c );
        System.out.println( e == d );
        
        String f = e.intern();
        
        System.out.println( f == d );
        //JAVA编译器对string + 基本类型/常量 是当成常量表达式直接求值来优化的。  运行期的两个string相加,会产生新的对象的,存储在堆(heap)中 
        String g = a + "xyz" ;//a为变量,在运行期才会被解析。 
        System.out.println( g == c );
        
        final String h = "abc" ;
        String i = h + "xyz" ;
        System.out.println( i == c );//h为常量,编译期会被优化  
        
    }

}

运行结果如下:

true
~~~~~~~~~~~~~~
false
false
true
false
true

String常用方法

 测试案例:

package ecut.strings;

import java.nio.charset.Charset;
import java.util.Arrays;

/**
 */
public class StringTest6 {

    public static void main(String[] args) {
        
        String s = "How old are you ? " ;
        System.out.println("1、求字符串长度");
        int len = s.length();
        System.out.println("字符串的长度"+len);
        System.out.println("2、求字符串某一位置字符");
        char ch = s.charAt(2);//索引范围为从 0 到 length() - 1。
        System.out.println("字符串第2+1个字符是"+ch);
        System.out.println("3、提取子串");
        String s1 = s.substring(2, 5);//beginIndex - 起始索引(包括) endIndex - 结束索引(不包括)。 
        String s2 = s.substring(18);//beginIndex 大于0小于等于String对象的长度,等于时返回空串。 
        System.out.println("子串s1为:"+s1);
        System.out.println("子串s2为"+s2);
        System.out.println("4、字符串比较");
        String str1 = new String("abc");
        String str2 = new String("ABC");
        int a = str1.compareTo(str2);//若当前对象比参数大则返回正整数,反之返回负整数,相等返回0。
        int b = str1.compareToIgnoreCase(str2);//忽略大小写
        System.out.println("若当前对象比参数大则返回正整数,反之返回负整数,相等返回0");
        boolean c = str1.equals(str2);//c=false
        boolean d = str1.equalsIgnoreCase(str2);//d=true
        System.out.println("比较当前字符串和参数字符串,在两个字符串相等的时候返回true,否则返回false。");
        System.out.println("5、字符串中单个字符查找");
        int in = s.indexOf('y');
        System.out.println("字符串中y的位置"+in);
        System.out.println("6、字符串中字符的大小写转换");
        String str3 = s.toLowerCase();
        String str4 = s.toUpperCase();
        System.out.println("转换为小写为"+str3);
        System.out.println("转换为大写为"+str4);
        System.out.println("7、字符串中字符的替换");
        String str5 = s.replace('o', 'a');
        System.out.println("a替换o后为"+str5);
        System.out.println("8、字符串连接");
        String str6 = s.concat(str1);
        System.out.println("str1和s连接后为"+str6);
        System.out.println("9、截去字符串两端的空格");
        String str7 = s.trim();
        System.out.println("s截去字符串两端的空格,但对于中间的空格不处理后为"+str7);
        System.out.println("10、比较起始字符或结尾字符是否一致");
        s.startsWith("a");
        System.out.println("用来比较当前字符串的起始字符或子字符串prefix和终止字符或子字符串suffix是否和当前字符串相同,重载方法中同时还可以指定比较的开
始位置offset。"); System.out.println("11、作为分隔符进行字符串分解"); String[] str8 = s.split(" "); for( String str : str8 ) { System.out.println(str); } System.out.println("12、判断是否包含字符串"); s.contains("ow"); System.out.println("判断参数是否被包含在字符串中,并返回一个布尔类型的值。"); System.out.println("13、字符串转换为基本类型"); int e = Integer.parseInt("12"); float f = Float.parseFloat("12.34"); double g = Double.parseDouble("1.124"); System.out.println("e="+e+",f="+f+",g="+g); System.out.println("14、基本类型转换为字符串"); String str9 = String.valueOf(12); System.out.println("str9为"+str9); System.out.println("15、将字符从此字符串复制到目标字符数组。 "); char[] chars = new char[ 10 ]; System.out.println( chars[ 0 ] == 'u0000' ); // 将字符串中的 [ 4 , 7 )之间的字符 复制到 chars 数组的下标是5的位置开始 s.getChars( 4 , 7 , chars , 5 );// getChars()方法,不是返回一个数组,而是复制数组
System.out.println("将字符串中的 [ 4 , 7 )之间的字符 复制到 chars 数组的下标是5的位置开始 "); System.out.println( Arrays.toString( chars ) ); } }



运行结果如下:

1、求字符串长度
字符串的长度18
2、求字符串某一位置字符
字符串第2+1个字符是w
3、提取子串
子串s1为:w o
子串s2为
4、字符串比较
若当前对象比参数大则返回正整数,反之返回负整数,相等返回0
比较当前字符串和参数字符串,在两个字符串相等的时候返回true,否则返回false。
5、字符串中单个字符查找
字符串中y的位置12
6、字符串中字符的大小写转换
转换为小写为how old are you ? 
转换为大写为HOW OLD ARE YOU ? 
7、字符串中字符的替换
a替换o后为Haw ald are yau ? 
8、字符串连接
str1和s连接后为How old are you ? abc
9、截去字符串两端的空格
s截去字符串两端的空格,但对于中间的空格不处理后为How old are you ?
10、比较起始字符或结尾字符是否一致
用来比较当前字符串的起始字符或子字符串prefix和终止字符或子字符串suffix是否和当前字符串相同,重载方法中同时还可以指定比较的开始位置offset。
11、作为分隔符进行字符串分解
How
old
are
you
?
12、判断是否包含字符串
判断参数是否被包含在字符串中,并返回一个布尔类型的值。
13、字符串转换为基本类型
e=12,f=12.34,g=1.124
14、基本类型转换为字符串
str9为12
15、将字符从此字符串复制到目标字符数组。 
true
将字符串中的 [ 4 , 7 )之间的字符 复制到 chars 数组的下标是5的位置开始 
[

StringBuffer和StringBuilder

1、StringBuffer

package ecut.strings;

public class StringBufferTest {

    public static void main(String[] args) {
        
        // s.value ==>  "abc".value ;
        // String s = "abcxyz";
        
        
        // char[] value = new char[ 3 + 16 ];
        // value[ 0 ] = 'a' ;  value[ 1 ] = 'b' ;  value[ 2 ] = 'c' ;
        StringBuffer sb = new StringBuffer( "abc" ); 
        
        // value[ 3 ] = 'x' ;  value[ 4 ] = 'y' ;  value[ 5 ] = 'z' ;
        sb.append( "xyz" );
        
        String x = sb.toString() ; 
        System.out.println( x );
        //返回字符串对象的规范化表示形式。
        String y = x.intern();
        
        System.out.println( x == y );
        
        System.out.println( "~~~~~~~~~~~~~~~~~~~~~~~~" );
        
        // 池中有几个串
        // "a"
        // "ab"
        // "abc"
        // "abcd"
        // "abcde"
        String str = "a" + "b" + "c" + "d" + "e" ;
        System.out.println( str );
        
        StringBuffer buffer = new StringBuffer();
        buffer.append( "a" );
        buffer.append( "b" );
        buffer.append( "c" );
        buffer.append( "d" );
        buffer.append( "e" );
        
        String r = buffer.toString();
        System.out.println( r );

    }

}

运行结果如下:

abcxyz
true
~~~~~~~~~~~~~~~~~~~~~~~~
abcde
abcde

2、StringBuilder

package ecut.strings;

public class StringBuilderTest {

    public static void main(String[] args) {
        
        StringBuilder builder = new StringBuilder();
        
        builder.append( "a" );
        builder.append( "b" );
        builder.append( "c" );
        builder.append( "d" );
        builder.append( "e" );
        
        System.out.println( builder );
        
        String r = builder.toString();
        System.out.println( r );
        //将此字符序列用其反转形式取代
        builder.reverse();
        
        System.out.println( builder );

    }

}

运行结果如下:

abcde
abcde
edcba

String、StringBuffer和StringBuilder区别
String 是被 final 修饰的,他的长度是不可变的,就算调用 String 的concat 方法,那也是把字符串拼接起来并重新创建一个对象,把拼接后的 String 的值赋给新创建的对象,而 StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象,调用StringBuffer 的 append 方法,来改变 StringBuffer 的长度,并且,相比较于 StringBuffer,String 一旦发生长度变化,是非常耗费内存的!StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。 append方法与直接使用+串联相比,减少常量池的浪费。

待解决问题

两幅图结果为什么不一样

参考博客链接

http://blog.csdn.net/ithomer/article/details/9936743

https://www.cnblogs.com/ITtangtang/p/3976820.html

转载请于明显处标明出处

http://www.cnblogs.com/AmyZheng/p/8453374.html

原文地址:https://www.cnblogs.com/AmyZheng/p/8453374.html