Java 7之基础类型第6篇 - Java可变字符串类型
2013-12-31 20:59
1131 查看
在实际的项目开发过程中,可能我们更多时候是在操作可变的字符串,例如,动态的拼接SQL语句。
之所以叫StringBuilder和StringBuffer为可变字符串是因为:
(1)提供了大量改变原字符串的操作,如append()方法。而改变是在原来字符串的基础上修改的,并不像String中的一些方法,通过new String()来返回一个新的字符串。
(2)字符串会自动扩容,不需要人为的进行操作,而String本身是不进行扩容的。
下面来详细了解一下这两个类的实现。首先来看一下AbstractStringBuilder类,
测试程序如下:
StringBuilder和StringBuffer类都实现了这个抽象类,只是StringBuffer类中公开的方法都加上了synchronized关键字进行同步,也是与StringBuilder的最大不同。
CharSequence是个接口,表示字符序列,而String、StringBuilder和StringBuffer都实现这个接口,底层都是通过数组来实现的。
String、StringBuilder、StringBuffer的异同点结合之前写的博文,我们对这三个常用的类的异同点进行分析:
异同点:
String的对象是不可变的;而StringBuilder和StringBuffer是可变的。
StringBuilder不是线程安全的;而StringBuffer是线程安全的
String中的offset,value,count都是被final修饰的不可修改的;而StringBuffer和StringBuilder中的value,count都是继承自AbstractStringBuilder类的,没有被final修饰,说明他们在运行期间是可修改的,而且没有offset变量。
相同点:
三个类都是被final修饰的,是不可被继承的。且都能表示表示字符序列(源代码中可以看出都继承了CharSequence.java类 )
之所以叫StringBuilder和StringBuffer为可变字符串是因为:
(1)提供了大量改变原字符串的操作,如append()方法。而改变是在原来字符串的基础上修改的,并不像String中的一些方法,通过new String()来返回一个新的字符串。
(2)字符串会自动扩容,不需要人为的进行操作,而String本身是不进行扩容的。
下面来详细了解一下这两个类的实现。首先来看一下AbstractStringBuilder类,
abstract class AbstractStringBuilder implements Appendable, CharSequence { // 基本的属性 char[] value; int count; // The count is the number of characters used. // 构造函数 AbstractStringBuilder() { } AbstractStringBuilder(int capacity) { value = new char[capacity]; } // 扩容 public int capacity() { return value.length; } public void ensureCapacity(int minimumCapacity) { if (minimumCapacity > 0) ensureCapacityInternal(minimumCapacity); } private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) expandCapacity(minimumCapacity); } /** * This implements the expansion semantics of ensureCapacity with no * size check or synchronization. */ void expandCapacity(int minimumCapacity) { // 要保证value字符数组足够大 int newCapacity = value.length * 2 + 2;// 扩展为原来长度的2倍加2 if (newCapacity - minimumCapacity < 0) newCapacity = minimumCapacity; if (newCapacity < 0) { if (minimumCapacity < 0) // overflow throw new OutOfMemoryError(); newCapacity = Integer.MAX_VALUE; } value = Arrays.copyOf(value, newCapacity);// 在扩容的时候都会进行原数据的复制 } }如上定义了一个字符数组,并没有加任何限制。还提供了扩容的方法和几个默认的构造方法。由于类继承了Appendable接口,而这个接口主要是定义了一类方法 - append()方法,在这个抽象类中都进行了实现:
public AbstractStringBuilder append(CharSequence s, int start, int end) { if (s == null) s = "null"; if ((start < 0) || (start > end) || (end > s.length())) throw new IndexOutOfBoundsException("start " + start + ", end " + end + ", s.length() " + s.length()); int len = end - start;// 需要复制的字符个数 ensureCapacityInternal(count + len); // 确保value字符数组足够大 for (int i = start, j = count; i < end; i++, j++) // 将字符串中包含的部分字符添加到value字符数组中 value[j] = s.charAt(i); count += len; return this; }有许多的append()方法,处理方法都非常类似,有兴趣的可以自己去看。append()方法只能在末尾进行追加,如果要对字符串中间进行插入,则可以使用insert()方法,举个例子:
public AbstractStringBuilder insert(int offset, String str) { if ((offset < 0) || (offset > length())) throw new StringIndexOutOfBoundsException(offset); if (str == null) str = "null"; int len = str.length(); ensureCapacityInternal(count + len); System.arraycopy(value, offset, value, offset + len, count - offset);// 从value中的指定位置向后腾出len个位置 str.getChars(value, offset); // 将str中包含的字符插入value的指定位置 count += len; return this; }可以看到,都会进行自动扩容,然后将str字符串中的字符插入到value中的指定位置。由于会自动扩容,所以在使用可变的字符串时,最好指定足够的容量,以防止进行扩容。因为底层需要进行数组的拷贝。
测试程序如下:
StringBuilder str =new StringBuilder("abc"); str.insert(1, "xx"); System.out.println(str.toString());// axxbc
StringBuilder和StringBuffer类都实现了这个抽象类,只是StringBuffer类中公开的方法都加上了synchronized关键字进行同步,也是与StringBuilder的最大不同。
CharSequence是个接口,表示字符序列,而String、StringBuilder和StringBuffer都实现这个接口,底层都是通过数组来实现的。
String、StringBuilder、StringBuffer的异同点结合之前写的博文,我们对这三个常用的类的异同点进行分析:
异同点:
String的对象是不可变的;而StringBuilder和StringBuffer是可变的。
StringBuilder不是线程安全的;而StringBuffer是线程安全的
String中的offset,value,count都是被final修饰的不可修改的;而StringBuffer和StringBuilder中的value,count都是继承自AbstractStringBuilder类的,没有被final修饰,说明他们在运行期间是可修改的,而且没有offset变量。
相同点:
三个类都是被final修饰的,是不可被继承的。且都能表示表示字符序列(源代码中可以看出都继承了CharSequence.java类 )
相关文章推荐
- Java基础知识强化69:基本类型包装类之Character案例(统计字符串中大写小写以及数字的次数)
- java 基础 基本类型和字符串之间转换
- Java基础知识学习三 (String类型,字符串处理)
- Java基础学习3(类型转换:自动类型转换 和 强制类型转换,字符串String)
- Java基础知识2.3.3--可变长度字符串
- java基础数据类型与字符串之间的转换
- 【java基础】在Java中实现基本数据类型与字符、字符串之间的转换
- Java 7之基础类型第5篇 - Java字符串类型
- Java基础——基本类型和包装类、基本类型和字符串之间的转换
- Python【基础:数据类型和变量 字符串和编码 list和tuple 条件判断 循环 dict和set】注意事项(与java,c比较)
- Java基础加强:静态导入及可变参数和增强for循环 ,基本数据类型的自动拆箱和装箱
- 【Java学习笔记】基础知识学习9【可变字符串】
- Java基础小知识——基本数据类型和字符串以及字节数组的转换
- 首页所有文章资讯Web架构基础技术书籍教程我要投稿更多频道 » 为什么Java要把字符串设计成不可变的
- Java基础知识强化59:String(字符串)和其他类型的相互转化
- Java基础加强<二>可变参数、增强for循环、基本类型的自动拆箱与装箱、枚举
- Java基础:第二十讲 Java基本类型与字符串之间的转换
- 小白成长记——Java基础之基本数据类型与字符串的相互转换
- JAVA基础复习十六-LinkedList、栈和队列数据类型、泛型、增强for循环、可变参数、Arrays工具类
- Java基础——基本类型和包装类、基本类型和字符串之间的转换