您的位置:首页 > 产品设计 > UI/UE

java字符串连接String、StringBuffer和StringBuilder

2015-04-11 14:49 519 查看
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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐