java中String, StringBuffere,StringBuilder, StringTokenizer的区别是啥?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java中String, StringBuffere,StringBuilder, StringTokenizer的区别是啥?相关的知识,希望对你有一定的参考价值。
能详细说下他们之间的区别吗
String类String类:
java.lang.String类,不属于8种基本数据类型,String是一个对象,表示字符串常量。
因为对象的默认值是null,所以String的默认值也是null,但它又是一种特殊的对象,有其他对象没有的特性。
new String()和new String("")都是声明一个新的空字符串,是空串不是null。区别:空串是经过new运算符分配了内存,即实际存在了(定义了)。而null则没有(只声明),调用null的字符串的方法会抛出空指针异常。
从根本上认识java.lang.String类和String池。
1、String类是final的,不可被继承。public final class String。
2、String类的本质是字符数组char[],并且其值不可改变。private final char value[];
3、String类对象有个特殊的创建方式,如String x="abc"; "abc"就表示一个字符串对象,而x是"abc"对象的地址,叫做"abc"引用。
4、Java运行时会维护一个String pool(String池),String池中的字符串内容不可重复,而一般对象(非String类)不存在这个缓冲池,并且创建的对象仅仅用于方法的堆栈区。
5、创建字符串的方式归纳起来有三种:
<1>、使用new关键字创建字符串,String s = new String("abc");
<2>、直接指定,String s = "abc";
<3>、使用串联生成新的字符串,String s = "ab" + "c";
String对象的创建:
1、当使用任何方式来创建一个字符串对象s时,JVM会拿这个s在String池中找是否存在内容相同的字符串对象。如果不存在,则在池中创建一个字符串s,否则,不在池中添加。
2、Java中,只要使用new关键字类创建对象,则一定会(在堆区或栈区)创建一个新对象。
3、使用直接指定或者使用纯字符串串联来创建String对象,则仅仅会检查维护String池中的字符串,池中没有就在池中创建一个,有则直接返回已有的字符串对象地址(引用)。绝不会在堆栈去再创建该String对象。
4、使用包含变量的表达式来创建String对象,则不仅会检查维护String池,而且还会在堆栈区创建一个String对象。
String的不可变性:
不可变字符串具有一个很大的有点:编译器可以把字符串设置为共享。
String类型是不可改变的,比如当你想改变一个String对象时,如:
String s = "abc";
s = "fuck";
JVM不会改变原来的对象("abc"),而是生成一个新的String对象("fuck",当然先检查String池中是否已经有"fuck"字符串对象,有则引用,无则新建),然后让s去指向它,如果原来那个"abc"没有任何对象引用它,虚拟机的垃圾回收机制会接收它。这样可以提高运行效率!
注意:Java中字符串内容的比较用的是专门的方法如equals,compareTo等。==比较的是字符串的引用是否相同。
StringBuffer类:
字符串变量。可修改的字符串序列,该类的对象实体内存空间可以自动改变大小,便于存放一个可变的字符序列。
StringBuffer类有3个构造方法:
StringBuffer()
StringBuffer(int size)
StirngBuffer(String s)
当使用第1个无参数的构造方法时,分配给该对象的实体初始容量可以容纳16个字符,当该扩展字符序列长度>16时,实体容量自动增加以适应新字符串。
当使用第2个构造方法,可以指定分配给该对象的实体的初始容量为参数size指定的字符个数。当对象实体长度>size时自动增加。
当使用第3个构造方法,分配给该对象的实体的初始容量为参数字符串s的长度+16个字符,当对象实体长度大于初始容量时,实体容量自动增加。
StringBuffer对象可以通过length()放发获取实体存放的字符序列长度。通过capacity()方法获取当前实体的实际容量。
StringTokenizer类:
使用java.util.StringTokenizer类,分析一个字符串并分解成可独立使用的单词。
StringTokenizer类有两个常用构造方法:
StringTokenizer(String s):为字符串s构造一个分析器。使用默认的分隔符集合,即空格符(若干个空格符被看做一个空格)、换行符、回车符、Tab符、进纸符(\f)。
StringTokenizer(String s, String dilim):为字符串s构造一个分析器。参数dilim中的字符被作为分隔符。
把StringTokenizer对象称作一个字符串分析器。一个分析器可以使用nextToken()方法逐个获取字符串中的语言符号(单词),每当调用nextToken()时,都将在字符串中获得下一个语言符号,每获得一个语言符号,字符串分析器中负责计数的变量值自动减1,该计数变量的初始值等于字符串中的单词数目(可以用StringTokenizer对象调用countTokens()方法获得计数值)。
如:
String str="we are stud,ents";
StringTokenizer fenxi = new StringTokenizer(str,", "); //使用空格和逗号做分隔符
int count=fenxi.countTokens();
while(fenxi.hasMoreElements())
String s = fenxi.nextToken();
System.out.println(s);
System.out.println("共有单词:"+count+"个。");
另外,StringTokenizer可以用String类的split函数代替
String str="abc;bcd;efg";
String[] splitStrs=str.split(";");
for(int i=0;i<splitStrs.length;i++)
System.out.println(splitStrs[i]);
StringBuilder类StringBuilder类是从 JDK 5 开始新增的,此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。与StringBuffer类相比,通常应该优先使用 StringBuilder 类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快。如果可能,建议优先采用该类,因为在大多数情况中,它比 StringBuffer 要快。注意:将 StringBuilder 的实例用于多个线程是不安全的。如果需要这样的同步,则建议使用 StringBuffer类 参考技术A Java中String,StringBuffer,StringTokenizer类
String类: java.lang.String类,不属于8种基本数据类型,String是一个对象,表示字符串常量。
因为对象的默认值是null,所以String的默认值也是null,但它又是一种特殊的对象,有其他对象没有的特性。
new String()和new
String("")都是声明一个新的空字符串,是空串不是null。区别:空串是经过new运算符分配了内存,即实际存在了(定义了)。而null则没有(只声明),调用null的字符串的方法会抛出空指针异常。 从根本上认识java.lang.String类和String池。
1、String类是final的,不可被继承。public final class
String。
2、String类的本质是字符数组char[],并且其值不可改变。private final char
value[];
3、String类对象有个特殊的创建方式,如String
x="abc"; "abc"就表示一个字符串对象,而x是"abc"对象的地址,叫做"abc"引用。
4、Java运行时会维护一个String pool(String池),String池中的字符串内容不可重复,而一般对象(非String类)不存在这个缓冲池,并且创建的对象仅仅用于方法的堆栈区。
5、创建字符串的方式归纳起来有三种:
<1>、使用new关键字创建字符串,String s = new
String("abc");
<2>、直接指定,String s =
"abc";
<3>、使用串联生成新的字符串,String s =
"ab" + "c";
String对象的创建:
1、当使用任何方式来创建一个字符串对象s时,JVM会拿这个s在String池中找是否存在内容相同的字符串对象。如果不存在,则在池中创建一个字符串s,否则,不在池中添加。
2、Java中,只要使用new关键字类创建对象,则一定会(在堆区或栈区)创建一个新对象。
3、使用直接指定或者使用纯字符串串联来创建String对象,则仅仅会检查维护String池中的字符串,池中没有就在池中创建一个,有则直接返回已有的字符串对象地址(引用)。绝不会在堆栈去再创建该String对象。
4、使用包含变量的表达式来创建String对象,则不仅会检查维护String池,而且还会在堆栈区创建一个String对象。 String的不可变性:
不可变字符串具有一个很大的有点:编译器可以把字符串设置为共享。
String类型是不可改变的,比如当你想改变一个String对象时,如:
String s = "abc";
s = "fuck";
JVM不会改变原来的对象("abc"),而是生成一个新的String对象("fuck",当然先检查String池中是否已经有"fuck"字符串对象,有则引用,无则新建),然后让s去指向它,如果原来那个"abc"没有任何对象引用它,虚拟机的垃圾回收机制会接收它。这样可以提高运行效率! 注意:Java中字符串内容的比较用的是专门的方法如equals,compareTo等。==比较的是字符串的引用是否相同。
StringBuffer类:
字符串变量。可修改的字符串序列,该类的对象实体内存空间可以自动改变大小,便于存放一个可变的字符序列。
StringBuffer类有3个构造方法:
StringBuffer()
StringBuffer(int size)
StirngBuffer(String s)
当使用第1个无参数的构造方法时,分配给该对象的实体初始容量可以容纳16个字符,当该扩展字符序列长度>16时,实体容量自动增加以适应新字符串。
当使用第2个构造方法,可以指定分配给该对象的实体的初始容量为参数size指定的字符个数。当对象实体长度>size时自动增加。
当使用第3个构造方法,分配给该对象的实体的初始容量为参数字符串s的长度+16个字符,当对象实体长度大于初始容量时,实体容量自动增加。
StringBuffer对象可以通过length()放发获取实体存放的字符序列长度。通过capacity()方法获取当前实体的实际容量。
StringTokenizer类:
使用java.util.StringTokenizer类,分析一个字符串并分解成可独立使用的单词。
StringTokenizer类有两个常用构造方法:
StringTokenizer(String s):为字符串s构造一个分析器。使用默认的分隔符集合,即空格符(若干个空格符被看做一个空格)、换行符、回车符、Tab符、进纸符(/f)。
StringTokenizer(String s, String
dilim):为字符串s构造一个分析器。参数dilim中的字符被作为分隔符。
把StringTokenizer对象称作一个字符串分析器。一个分析器可以使用nextToken()方法逐个获取字符串中的语言符号(单词),每当调用nextToken()时,都将在字符串中获得下一个语言符号,每获得一个语言符号,字符串分析器中负责计数的变量值自动减1,该计数变量的初始值等于字符串中的单词数目(可以用StringTokenizer对象调用countTokens()方法获得计数值)。
如:
String str="we are
stud,ents";
StringTokenizer fenxi = new
StringTokenizer(str,", "); //使用空格和逗号做分隔符
int count=fenxi.countTokens();
while(fenxi.hasMoreElements())
String s = fenxi.nextToken();
System.out.println(s);
System.out.println("共有单词:"+count+"个。"); 另外,StringTokenizer可以用String类的split函数代替
String str="abc;bcd;efg";
String[]
splitStrs=str.split(";");
for(int i=0;i<splitStrs.length;i++)
System.out.println(splitStrs[i]);
参考资料:编程吧-Java社区 28mike 。 com
参考技术B StringBuffere 带有 缓冲区,效率比较高,不用 经常分配内存 参考技术C string 就是一个字符串stringbuffered 是一个由二进制组成的串
stringTokenizer 是可以把string串通过关键字拆分成几组的方法
java中貌似灭有sringbuilder
vb里面有stringbuilder 和java中的stringbuffered一样 参考技术D StringBuffer和StringBuilder的本质是一个字符串的数组,便于修改,你可以看看他们的源代码。他们俩的区别是StringBuffer是同步的 第5个回答 2012-09-04 楼上说得很清楚了
java中String,StringBuilder,StringBuffer实现原理,优化
在java中字符串使我们编程时经常需要使用的类型,java中提供了String、StringBuilder、StringBuffer等相关字符串操作类。
首先来看String,JDK中String的实现是一个final类,其内部主要还是一个char数组组成。
public final class String
implements java.io.Serializable, Comparable, CharSequence
/** The value is used for character storage. */
private final char value[];
…
之所以要定义为final类型,是因为String的hash算法是和char数组相关的:
public int hashCode()
int h = hash;
if (h == 0 && value.length > 0)
char val[] = value;
for (int i = 0; i < value.length; i++)
h = 31 * h + val[i];
hash = h;
return h;
并且String一旦初始化之后,后面就不能在对这个String实例的内容进行更新,只能生成一个新的。
主要还是因为这里String的hashCode计算方式是和value数组相关的。是通过value数组计算得到的。如果我们修改了value值,那么String的hashCode就会发生改变,而JDK中很多实现都是依赖于hashCode的,比如map。我们开始放入了一个key为String的对象,如果我们修改value数组,那么后续我们无法获取到这个key对应的值了(map的key是需要hashCode运算的)。
另外一个很经典的问题:
String a = "Hello World";
String b = new String("Hello World");
System.out.println(a == b );
System.out.println(a.equals(b));
System.out.println(a == b.intern());
这里会输出:
false
true
true
首先需要明确的一点是:
String a = "Hello World";
这里的Hello World
是一个字符串常量,这块内存布局如下:
这里的 String a = "Hello World";
中 “Hello World”;这个是在常量池里面分配的,a的引用是直接指向常量池的。
而b是在堆上分配的,b的引用是指向堆上的对象的的。
而如果调用了String.inern方法,那么返回的是一个字符串常量池的对象,我们可以看看这个方法的定义:
/**
* Returns a canonical representation for the string object.
* <p>
* A pool of strings, initially empty, is maintained privately by the
* class @code String.
* <p>
* When the intern method is invoked, if the pool already contains a
* string equal to this @code String object as determined by
* the @link #equals(Object) method, then the string from the pool is
* returned. Otherwise, this @code String object is added to the
* pool and a reference to this @code String object is returned.
* <p>
* It follows that for any two strings @code s and @code t,
* @code s.intern() == t.intern() is @code true
* if and only if @code s.equals(t) is @code true.
* <p>
* All literal strings and string-valued constant expressions are
* interned. String literals are defined in section 3.10.5 of the
* <cite>The Java™ Language Specification</cite>.
*
* @return a string that has the same contents as this string, but is
* guaranteed to be from a pool of unique strings.
*/
public native String intern();
```
可以看到intern方法返回是一个和当前String对象拥有相同内容的字符串常量池对象,如果字符串常量池没有会创建一个,如果已经有了,那么直接返回。
` String a = "Hello World";``这种方式分配的对象是直接在字符串常量池中的,与b.intern(0的常量池对象是同一个。
#### StringBuilder
StringBuilder相比String而言其实大体差不多,底层也是有一个char数组,但是其数组是可变的。
```
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
.....
```
StringBuilder是继承自AbstractStringBuilder,StringBuffer也是,只不过相关方法StringBuffer增加了synchronized同步语义。
StringBuilder默认初始容量是16,当我们使用append的时候,实现如下:
```java
public AbstractStringBuilder append(String str)
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
private void ensureCapacityInternal(int minimumCapacity)
// overflow-conscious code
if (minimumCapacity - value.length > 0)
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
```
`ensureCapacityInternal`是确保底层char数组有足够大的容量来容纳字符内容,如果不够将进行扩容,通过`Arrays.copyOf()`对原数组进行扩容。
`AbstractStringBuilder`中还有一个属性`count`,用来标记当前数组中有多少个元素被填充,coutn <= value.length
这样,我们每次append数组的时候,如果容量不够都会进行扩容。
而StringBuider的toString方法很简单粗暴:
```java
public String toString()
// Create a copy, don't share the array
return new String(value, 0, count);
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;
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count)
throw new StringIndexOutOfBoundsException(offset + count);
this.value = Arrays.copyOfRange(value, offset, offset+count);
```
就是将当前StringBuilder的value数组复制到String的value数组中去。
实际上如果我们再初始StringBuilder的时候可以将容量放大一点,这样可以避免在append过程中不断进行数组的扩容复制。
另外一个就是StringBuilder提供了一个`setLength`方法:
```java
public void setLength(int newLength)
if (newLength < 0)
throw new StringIndexOutOfBoundsException(newLength);
ensureCapacityInternal(newLength);
if (count < newLength)
Arrays.fill(value, count, newLength, '\\0');
count = newLength;
```
可以看到如果新的大小比已有的内容大小大,那么会进行扩容并填充``\\0\\,如果不是,那么直接重设` count = newLength;`
如果我们`setLength(0)`那么原有分配的数组不会被回收内容不变,只是count=0,这样后续append的时候,就会覆盖之前的内容。
#### StringBuffer
StringBuffer基本上与StringBuilder一样,但是在append方法上会加上synchronized同步语义
以上是关于java中String, StringBuffere,StringBuilder, StringTokenizer的区别是啥?的主要内容,如果未能解决你的问题,请参考以下文章
重温java中的String,StringBuffer,StringBuilder类
java中string,stringBuffer和StringBuider
java中String,StringBuilder,StringBuffer实现原理,优化