java字符串连接String、StringBuffer和StringBuilder

Java字符串连接再开发中随时用的,方法很多:

先看下下边的代码:

package com.meiyabaike.classx;

public class ClassxMathCalculate {
    public static void main(String[] args) {
        int i1 = 10;
        int i2 = 20;
        System.out.println("resultx1 :"+i1+i2);
        //Error: the operator - is undefined for the argument type(s) String, int
//        System.out.println("resultx2 :"+i1-i2);
        System.out.println("resultx3 :"+i1*i2);
        System.out.println("resultx4 :"+i1/i2);
        System.out.println("resultx5 :"+i1%i2);
    }
}

它输出是什么呢?为什么第二行被注释呢?

字符串String、StringBuffer和StringBuilder,都是由字符数组char[]实现,:

在 Java的String类中(jdk 1.0):

...
 * @author  Lee Boynton
 * @author  Arthur van Hoff
 * @version 1.204, 06/09/06
 * @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
{
    /** The value is used for character storage. */
    private final char value[];

    /** The offset is the first index of the storage that is used. */
    private final int offset;

    /** The count is the number of characters in the String. */
    private final int count;

    /** Cache the hash code for the string */
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;
...
    /**
     * Creates an AbstractStringBuilder of the specified capacity.
     */
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

可以看出,用于存放字符的数组、和第一个索引的存储(偏移量)和字符串字符数被声明为final的,因此只能赋值一次,不可再更改.

字符串常量,字符串长度不可变。Java中String是immutable(不可变)的。

String对象不是原始类型.

String对象为不可变对象,一旦被创建,就不能修改它的值.

对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去.

String 是final类,即不能被继承.

一般使用都是:

        String s1 = "aaa";
        System.out.println(s1 + "String");
        s1 += "bbb";
        System.out.println(s1);

输出为:

aaaString
aaabbb

Java算数基本运算符:+ - * / %

在算数运算中,

乘、除、求余同优先级

加减为同优先级

乘、除、求余优先于加减

算数运算时:按照从左向右的顺序计算

[以及程序执行,自上而下,自左向右]

如: System.out.println(3*4/2%5);

输出:1

Java中"+"作为字符串连接符,现在看看,最上边的输出结果:

resultx1 :1020
resultx3 :200
resultx4 :0
resultx5 :10

第一条result1("resultx1 :"+i1+i2):

"resultx1 :"+i1为字符串连接,结果为resultx1 :10,其结果也为字符串类型,然后,"resultx1 :10"+20,也为为字符串连接,最终结果resultx1 :1020

第二条result2("resultx2 :"+i1-i2):

"resultx2:"+i1为字符串连接,结果为resultx2 :10,其结果也为字符串类型,然后,"resultx :10" -20,为字符串 int类型,可 为算数运算符,不能用作字符串连接或者算数运算使用

编译报错:符号不能用于字符串和int之间,编译错误

第三条result3(resultx3 :"+i1*i2):

因为* / %运算优先级高于+ - ,所以不能在自左向右,而要先进行* / %运算,则此输出,相当于字符串"resultx3 :"+表达式,结果为resultx3 :200

其他第四、五都是和三条一致了。

而第四条输出为0,而不是0.5呢?

int i1 = 10;
int i2 = 20;
System.out.println((double)i1/i2);
System.out.println(i1/i2);

输出为:

0.5
0

因为:

当参加算数运算的两个操作数的数据类型不同时,所得结果的数据类型与精度较高(或位数更长)的那种数据类型一致。

在java的StringBuffer(jdk 1.0)类:

String对象是不可变对象,每次操作Sting 都会重新建立新的对象来保存新的值.

StringBuffer对象实例化后,只对这一个对象操作。

 * @author	Arthur van Hoff
 * @version 	1.101, 11/17/05
 * @see     java.lang.StringBuilder
 * @see     java.lang.String
 * @since   JDK1.0
 */
 public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    static final long serialVersionUID = 3388685877147921107L;

    /**
     * Constructs a string buffer with no characters in it and an
     * initial capacity of 16 characters.
     */
    public StringBuffer() {
	super(16);
    }
    /**
     * Constructs a string buffer with no characters in it and
     * the specified initial capacity.
     *
     * @param      capacity  the initial capacity.
     * @exception  NegativeArraySizeException  if the <code>capacity</code>
     *               argument is less than <code>0</code>.
     */
    public StringBuffer(int capacity) {
	super(capacity);
    }
 * @author	Michael McCloskey
 * @version 	1.15, 11/17/05
 * @since	1.5
 */
abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * The value is used for character storage.
     */
    char value[];

    /**
     * The count is the number of characters used.
     */
    int count;
   ...
    /**
     * Creates an AbstractStringBuilder of the specified capacity.
     */
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }
 ...

先看看下边代码:

package com.meiyabaike.classx;

public class EfficiencyString {
    public static void main(String[] args) {
        String str = "a";
        StringBuffer sf = new StringBuffer("a");
        StringBuilder su = new StringBuilder("a");
        Runtime rt = Runtime.getRuntime();
        long sfm = rt.freeMemory();
        long stm = System.currentTimeMillis();
        for(int i = 0; i < 10000; i++){
               str += i;
//            sf.append(i);
//            su.append(i);
        }
        long efm = rt.freeMemory();
        long etm = System.currentTimeMillis();
        System.out.println("字符串连接耗时:" + (etm - stm)+" ms,内存消耗:" + (sfm - efm) / 1024 + "KB");

    }
}

执行10000次连接字符串结果依次是,自己打开注释:

String:5000次连接:字符串连接耗时:85 ms,内存消耗:5762KB

StringBuffer:字符串连接耗时:13 ms,内存消耗:335KB

StringBuiler:字符串连接耗时:12 ms,内存消耗:335KB

String:10000次连接:字符串连接耗时:337 ms,内存消耗:-148610KB     //(***)

字符串变量(Synchronized,即线程安全),操作方法都为同步synchronized方法。
如果要频繁对字符串内容进行修改,出于效率考虑最好使用StringBuffer,如果想转成String类型,可以调用StringBuffer的toString()方法。

StringBuffer线程安全的可变字符序列。在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。可将字符串缓冲区安全地用于多个线程。

StringBuffer上的连接主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。
每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。
append方法始终将这些字符添加到缓冲区的末端;
insert方法则在指定的点添加字符。

        StringBuffer sf = new StringBuffer("a1b3c5");
        System.out.println(sf.toString());
        sf.append("d7");
        System.out.println(sf.toString());
        sf.insert(3,"AA");
        System.out.println(sf.toString());

输出为:
a1b3c5
a1b3c5d7
a1bAA3c5d7

构造方法:

StringBuffer ();            //默认分配16个字符的空间
StringBuffer (int size);  //分配size个字符的空间
StringBuffer (String str);  //分配str.length()+16个字符的空间 

创建StringBuffer,可以用构造函数来设定它的初始化容量,这样可以明显地提升性能.

构造函数是StringBuffer(int length),length参数表示当前的StringBuffer能保持的字符数量。

也可以使用ensureCapacity(int minimumcapacity)方法在StringBuffer对象创建之后设置它的容量。

StringBuffer在内部维护一个字符数组,当你使用缺省的构造函数来创建StringBuffer对象的时候,因为没有设置初始化字符长度,StringBuffer的容量被初始化为16个字符,也就是说缺省容量就是16个字符。

当StringBuffer达到最大容量的时候,它会将自身容量增加到当前的2倍再加2,也就是(2*旧值+2)。

如果你使用缺省值,初始化之后接着往里面追加字符,在你追加到第16个字符的时候它会将容量增加到34(2*16+2),当追加到34个字符的时候就会将容量增加到 70(2*34+2)。只要StringBuffer到达它的最大容量它就不得不创建一个新的字符数组然后重新将旧字符和新字符都拷贝一遍到新建。给StringBuffer设置一个合理的初始化容量值可以对StringBuffer性能增益。

在java的StringBuilder(jdk 1.5)类:

 * @author	Michael McCloskey
 * @version 	1.11, 11/17/05
 * @see         java.lang.StringBuffer
 * @see         java.lang.String
 * @since	1.5
 */
public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

    /** use serialVersionUID for interoperability */
    static final long serialVersionUID = 4383685877147921099L;

    /**
     * Constructs a string builder with no characters in it and an
     * initial capacity of 16 characters.
     */
    public StringBuilder() {
	super(16);
    }

StringBuilder:字符串变量(非线程安全)。
在内部,StringBuilder对象被当作是一个包含字符序列的变长数组,是一个可变的字符序列。
此类提供一个与 StringBuffer 兼容的 API,但不保证同步。
该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候。

String、StringBuffer和StringBuilder区别:

String是不可变的字符串对象, 每次要对String类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String对象,所以经常改变内容的字符串最好不要用String,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后,JVM的GC就会开始工作,性能就会降低。
使用StringBuffer类时,每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。所以多数情况下推荐使用StringBuffer,特别是字符串对象经常改变的情况下。
在某些特别情况下,
String s = "a" + "b" + "c";相当于StringBuffer sf = new StringBuilder("a").append("b").append("c");
String对象的字符串拼接其实是被Java Compiler编译成了StringBuffer对象的拼接,所以这些时候String对象的速度并不会比StringBuffer对象慢。
但要注意的是,如果拼接的字符串来自另外的String对象的话,Java Compiler就不会自动转换了,速度也就慢了。
String a = "a";
String b = "b";
String c = "c";
String d = a + b + c;
此情况,Java Compiler会按照原来的方式去做,String的concatenation(即+)操作利用了StringBuilder(或StringBuffer)的append方法实现,此时,对于上述情况,若a,b,c采用String定义,拼接时需要额外创建一个StringBuffer(或StringBuilder),之后将StringBuffer转换为String;

若采用StringBuffer(或StringBuilder),则不需额外创建StringBuffer。

综上:

如果使用少量的字符串操作,使用String;

如果频繁的对大量字符串进行操作,则使用

1:全局变量或者需要多线程支持则使用StringBuffer;

2:局部变量或者单线程不涉及线程安全则使有StringBuilder。

时间: 2024-12-31 13:16:52

java字符串连接String、StringBuffer和StringBuilder的相关文章

在Java web应用中,处理字符串是用stringbuffer还是stringbuilder

问题描述 在Java web应用中,处理字符串是用stringbuffer还是stringbuilder 两者之间的差别就在于线程安全的问题上.一直都搞不明白,在web应用中多次请求同一个方法,需不需要考虑线程安全问题. 在这种情况下,是需要使用哪一个.是不是还应该分局部变量和全局变量来说. 刚接触这个,求大神们解答,实在搞混了 解决方案 StringBuffer 与 StringBuilder 中的方法和功能完全是等价的,只是StringBuffer 中的方法大都采用了 synchronize

JAVA字符串格式化-String.format()的使用_java

本篇介绍JAVA字符串格式化-String.format()的使用,具体如下: 常规类型的格式化 String类的format()方法用于创建格式化的字符串以及连接多个字符串对象.熟悉C语言的同学应该记得C语言的sprintf()方法,两者有类似之处.format()方法有两种重载形式. format(String format, Object... args) 新字符串使用本地语言环境,制定字符串格式和参数生成格式化的新字符串. format(Locale locale, String for

Java那点事——StringBuffer与StringBuilder原理与区别_java

最近在找工作,考官问我一个简单的题目:"StringBuffer与StringBuilder的区别,它们的应用场景是什么?",下面小编答案分享给大家,方便以后大家学习,以此也做个备录. 其实只要找下Google大神就有答案了:StringBuffer 与 StringBuilder 中的方法和功能完全是等价的,只是StringBuffer 中的方法大都采用了 synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是线程不安全

String,StringBuffer与StringBuilder

这次需要好好理顺一下这三个类 String 字符串常量 StringBuffer 字符串变量(线程安全) StringBuilder 字符串变量(非线程安全)  简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产

Java字符串连接性能

  剑字有19种写法,Java中字符串连接也有好多种写法,比如要连接6个字符串,以下5种写法都是可以的,究竟哪种写法最简捷,哪种最高效呢.     public static String concat1(String s1, String s2, String s3, String s4, String s5, String s6) {        String result = "";        result += s1;        result += s2;      

[Java开发之路](4)String、StringBuffer与StringBuilder详解

最近学习到字符串,整理了一下String,StringBuffer,StringBuilder相关知识 1. String String 类位于 java.lang 包中.String 对象创建后则不能被修改,是不可变的,所谓的修改其实是创建了新的对象,所指向的内存空间不同. String str1 = "xiaosi"; str1 = "欢迎你 " + str1; System.out.println(str1); // 欢迎你 xiaosi 通过观察运行结果可以

String,StringBuffer, StringBuilder 的区别

String,StringBuffer, StringBuilder 的区别 String和StringBuffer的区别,网上资料可以说是数不胜数,但是看到这篇文章,感觉里面做的小例子很有代表性,所以转一下,并自己做了一点总结. 在java中有3个类来负责字符的操作. 1.Character 是进行单个字符操作的, 2.String 对一串字符进行操作.不可变类. 3.StringBuffer 也是对一串字符进行操作,但是可变类. String:是对象不是原始类型.为不可变对象,一旦被创建,就

Java字符串拼接效率分析及最佳实践

本文来源于问题 Java字符串连接最佳实践? java连接字符串有多种方式,比如+操作符,StringBuilder.append方法,这些方法各有什么优劣(可以适当说明各种方式的实现细节)? 按照高效的原则,那么java中字符串连接的最佳实践是什么? 有关字符串处理,都有哪些其他的最佳实践? 废话不多说,直接开始, 环境如下: JDK版本: 1.8.0_65 CPU: i7 4790 内存: 16G 直接使用+拼接 看下面的代码: @Test      public void test() {

从源代码的角度聊聊java中StringBuffer、StringBuilder、String中的字符串拼接

长久以来,我们被教导字符串的连接最好用StringBuffer.StringBuilder,但是我们却不知道这两者之间的区别.跟字符串相关的一些方法中总是有CharSequence.StringBuffer.StringBuilder.String,他们之间到底有什么联系呢? 1.从类的定义看CharSequence.StringBuffer.StringBuilder.String的关系 下面先贴上这四者的定义(来自JDK1.6) CharSequence是一个定义字符串操作的接口,Strin