最近看了点java字符串的知识。主要是看了编程思想这本书和JDK中源码和官方文档的。这篇文章是不涉及最基础的String、StringBuilder和StringBuffer的编程的,这些在我的另一篇博客上是有介绍。这篇算是在深入了解字符串后的一点个人理解。
字符串类首先就是指String类。String类是一个不变的对象,就是如果你想改变某个String类对象的内容。这种做法的后果就是产生一个新的String类对象。原来的String类对象是不会发生变化的。当我们new了一个String类对象,接下来要做的就是对实例对象的操作。首先我想说的就是String类是没有add、remove方法的。那String类实例如果想添加字符该怎么办呢?
一般我们的做法如下:
char data[] = {'a', 'b', 'c'};
String str = new String(data);
System.out.println(str +"abc" );
String cde = "cde";
System.out.println("abc" + cde);
注意String类使用了操作符+、+=来完成字符串的连接添加操作(这两个操作符可以说是Java中唯一的重载操作符)。对于所有的关于String类的操作,但凡返回的字符串和源字符串是不同的,这时就表明有新的String类对象的生成。
接下来要说的就是StringBuffer和StringBuilder这两个类。首先在最新的jdk中我们发现这两个都继承AbstractStringBuilder这个抽象类。只不过StringBuffer是线程同步的,而StringBuilder是单线程的。它们拥有的操作和方法几乎是一样的。
首先这两个类都是可变的字符序列。就是一个类似String类的带有缓冲区的字符串。缓冲区的初始化容量是16,虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。
这里我们经常使用的append()和insert()方法。就是在StringBuffer类的实例中不停的添加字符串。但是这些被修改的内容实际上是在缓冲区中,所以StringBuffer类对象改变字符串的长度和内容是不会产生新的StringBuffer类对象的。可以说这样做可以避免生成不必要的字符串对象。在一般的使用中最后当我们需要String类的时候,只需使用toString()方法即可将StringBuffer和StringBuilder类转换为String类。
使用StringBuffer和StringBuilder类的目的实际上就是在产生最终的那个String类对象前我是没有必要产生那么多的String类。但是如果开始就使用String类的话,中间的任何一个修改内容的操作环节都会产生新的String对象。而这些对象只是中间变量但却占据着内存。这种设计程序的行为是不妥的,所以建议使用StringBuffer和StringBuilder这两个类来进行前期的一系列的操作,只需在最后一步上使用toString()方法转换为String类即可。在StringBuffer和StringBuilder类中,由于同步会占用一定的时间所以会导致执行的速度受影响。所以在实际中一般优先使用单线程的StringBuiler类定义字符串。
最后在谈谈jdk中看到的这3个类的源码。我们发现在源码中是将字符串首先转换为字符数组(char [])的。接着所有的操作都是围绕字符数组引用展开的。即增删改查和判断等操作都是基于字符数组的,而且都会使用到数组索引的。当然在截取子字符串的时候会使用System的arraycopy()方法的。
格式如下:
public static void arraycopy(Object src,
int srcPos,
Object dest,
int destPos,
int length)
解释:从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组指定位置结束。从 src 引用的源数组到 dest 引用的目标数组,数组组件的一个子序列被复制下来。被复制的组件的编号等于 length 参数。源数组中位置在 srcPos 到 srcPos+length-1 之间的组件被分别复制到目标数组中的 destPos 到 destPos+length-1 位置。