浅谈java中的String、StringBuffer、StringBuilder类的区别以及关系
2017-10-21 08:24
549 查看
在java中最常见的使用就是对字符串的操作:首先先说一下对字符串的理解:字符串就是一连串字符序列,Java提供了String和StringBuffer两个类来封装字符串,并提供一系列方法来操作字符串对象。接下来对它们一一描述:
String类是不可变类:
即一旦一个String对象被创建以后,包含在这个对象中的字符串是不可改变的,直到这个对象被销毁。
StringBuffer类:
在java中则代表一个字符序列可变的字符串,即一个StringBuffer被创建以后,StringBuffer提供的append()、insert()、reverse()、setChatAt()、setLength()等方法可以改变这个字符串对象的字符序列。一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString()方法将其转换为一个String对象。
StringBuilder类:
它是在jdk1.5新增的一个StringBuilder类,它也代表字符串对象,在这里重点说一下StringBuilder和StringBuffer基本相似,它们底层的构造器基本相同,不同的是StringBuffer是线程安全的,而StringBuilder则没有实现线程安全功能的,正因为这个原因,它的性能较好一些。。。
来点刺激的String的源码:
可以看出String是由char[]来实现的,String是final类,也就意味着String类是不可以继承的
注意:刚开始说String是不可以变的就是因为char[]在是private的,并且String类没有提供setter方法,导致无法改变这个String对象 String s = “123456”中的s是对象的引用,对象的引用指向对象。对象是不可变的,但是对象的引用是可变的。
下面分析看一下它们中的方法的源码:
substring
concat
replace
可以发现subString、concat、replace操作都是不是在原字符串进行的,而是创建了一个新的字符串。也就是说,进行了上述操作后,本身的字符串并没有改变。只是返回了一个新的对象的引用。。。
对String操作的任何改变都不会改变原对象,而任何改变String对象的操作都会产生新对象。
如:
在这里会产生五个字符串直接量不但有原先的3个还会产生额外两个字符串直接量“javastruts”和“javastrutsspring”。程序中的str1依次指向3个不同的字符串对象。
因为String是不可变的,所以会产生很多的临时变量,在这里就会选择StringBuffer或者StringBuilder,因为它们就会解决这个问题
StringBuffer、StringBuilder有两个属性:length和capacity。
其中length属性表示其包含的字符序列的长度。与String对象length不同的是,StringBuffer、StringBuilder的length是可以改变的,可以通过length()、setLength(int len)方法来访问和修改其字符串序列的长度,capacity属性表示StringBuilder容量,capacity通常比length大,程序通常无须任何关心capacity属性。
通过反编译可以看出每次循环一次都会new 一个StringBuilder对象,然后进行append操作,最后用toString方法返回String对象。试想一下如果这些对象没有被JVM回收,则会造成多大的资源浪费。实际上jvm不傻,他会自动优化为:
再看一段代码:
反编译其字节码文件,可以看出new操作只进行了一次,也就是说只生成一个对象,append操作是在原有对象上进行的,因此在循环10000次之后,资源消耗要小得多。
再讲述一下StringBuffer,比StringBuilder多了一个关键字: synchronize。这个关键字在多线程操作的时起到安全保护的作用。
总结:如果在对字符串修改较少的情况下,建议使用String str = “Hello”;这种形式;如果在对字符串修改较多,则用StringBuilder;涉及到多线程,则用StringBuffer。
String类是不可变类:
即一旦一个String对象被创建以后,包含在这个对象中的字符串是不可改变的,直到这个对象被销毁。
StringBuffer类:
在java中则代表一个字符序列可变的字符串,即一个StringBuffer被创建以后,StringBuffer提供的append()、insert()、reverse()、setChatAt()、setLength()等方法可以改变这个字符串对象的字符序列。一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString()方法将其转换为一个String对象。
StringBuilder类:
它是在jdk1.5新增的一个StringBuilder类,它也代表字符串对象,在这里重点说一下StringBuilder和StringBuffer基本相似,它们底层的构造器基本相同,不同的是StringBuffer是线程安全的,而StringBuilder则没有实现线程安全功能的,正因为这个原因,它的性能较好一些。。。
来点刺激的String的源码:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0 private static final long serialVersionUID = -6849794470754667710L; private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0]; ...
可以看出String是由char[]来实现的,String是final类,也就意味着String类是不可以继承的
注意:刚开始说String是不可以变的就是因为char[]在是private的,并且String类没有提供setter方法,导致无法改变这个String对象 String s = “123456”中的s是对象的引用,对象的引用指向对象。对象是不可变的,但是对象的引用是可变的。
下面分析看一下它们中的方法的源码:
substring
public String substring(int beginIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } int subLen = value.length - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } return (beginIndex == 0) ? this : new String(value, beginIndex, subLen); } public String substring(int beginIndex, int endIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } if (endIndex > value.length) { throw new StringIndexOutOfBoundsException(endIndex); } int subLen = endIndex - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen); }
concat
public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } int len = value.length; char buf[] = Arrays.copyOf(value, len + otherLen); str.getChars(buf, len); return new String(buf, true); }
replace
public String replace(char oldChar, char newChar) { if (oldChar != newChar) { int len = value.length; int i = -1; char[] val = value; /* avoid getfield opcode */ while (++i < len) { if (val[i] == oldChar) { break; } } if (i < len) { char buf[] = new char[len]; for (int j = 0; j < i; j++) { buf[j] = val[j]; } while (i < len) { char c = val[i]; buf[i] = (c == oldChar) ? newChar : c; i++; } return new String(buf, true); } } return this; }
可以发现subString、concat、replace操作都是不是在原字符串进行的,而是创建了一个新的字符串。也就是说,进行了上述操作后,本身的字符串并没有改变。只是返回了一个新的对象的引用。。。
对String操作的任何改变都不会改变原对象,而任何改变String对象的操作都会产生新对象。
如:
String str1 = "java"; str1 = str1 + "struts"; str1 = str1 + "spring";
在这里会产生五个字符串直接量不但有原先的3个还会产生额外两个字符串直接量“javastruts”和“javastrutsspring”。程序中的str1依次指向3个不同的字符串对象。
因为String是不可变的,所以会产生很多的临时变量,在这里就会选择StringBuffer或者StringBuilder,因为它们就会解决这个问题
StringBuffer、StringBuilder有两个属性:length和capacity。
其中length属性表示其包含的字符序列的长度。与String对象length不同的是,StringBuffer、StringBuilder的length是可以改变的,可以通过length()、setLength(int len)方法来访问和修改其字符串序列的长度,capacity属性表示StringBuilder容量,capacity通常比length大,程序通常无须任何关心capacity属性。
public static void main(String[] args) { String str = ""; for(int i = 0;i < 10000;i++) str += "Hello"; }
通过反编译可以看出每次循环一次都会new 一个StringBuilder对象,然后进行append操作,最后用toString方法返回String对象。试想一下如果这些对象没有被JVM回收,则会造成多大的资源浪费。实际上jvm不傻,他会自动优化为:
StringBuilder sb = new StringBuilder(string); sb.append("Hello"); str.toString();
再看一段代码:
public static void main(String[] args) { StringBuilder sb = new StringBuilder(); for(int i = 0;i < 10000;i++) sb.append("Hello"); }
反编译其字节码文件,可以看出new操作只进行了一次,也就是说只生成一个对象,append操作是在原有对象上进行的,因此在循环10000次之后,资源消耗要小得多。
再讲述一下StringBuffer,比StringBuilder多了一个关键字: synchronize。这个关键字在多线程操作的时起到安全保护的作用。
总结:如果在对字符串修改较少的情况下,建议使用String str = “Hello”;这种形式;如果在对字符串修改较多,则用StringBuilder;涉及到多线程,则用StringBuffer。
相关文章推荐
- Java中String、StringBuilder以及StringBuffer区别和关系
- Java String 、 StringBuffer 、StringBuilder类的关系和区别
- java中String和StringBuffer以及StringBuilder的区别
- java 的String, Stringbuffer, StringBuilder的区别以及对final关键字的理解
- Java面试——String、StringBuider以及StringBuffer的区别和使用场景
- java中String和StringBuffer以及StringBuilder的区别
- java中的StringBuilder类的使用, String、StringBuilder、StringBuffer的区别
- JAVA的StringBuffer类(转载整理)____非常重要的一个类,线程安全,不用每次创建一个对象,以及和String的区别
- 转:浅谈Java中数据在内存中的状态,以及String、StringBuffer、==、equals、数组等问题
- 浅谈Java中数据在内存中的状态,以及String、StringBuffer、==、equals、数组等问题
- 【Java基础之String、StringBuilder、StringBuffer】Java中的String、StringBuilder以及StringBuffer的区别
- Java String、StringBuffer和StringBuilder类的区别
- Java中String、StringBuilder以及StringBuffer的区别
- Java基础之String,StringBuffer与StringBuilder的区别浅谈
- java中字符串操作string、stringBuffer和stringBuilder的区别以及其相关操作技术
- Java基础——浅谈String、StringBuffer和StringBuilder的区别
- java核心API之String,StringBuffer和StringBuilder以及equals与==的区别和联系
- 浅谈Java中数据在内存中的状态,以及String、StringBuffer、==、equals、数组等问题
- JAVA中String与StringBuffer以及StringBuilder的区别