Java中定义了三种字符串类型。
String与StringBuffer以及StringBuilder。
从名字上来看给人的感觉StringBuffer与StringBuilder是String的延伸。但这是错误的,事实是这三种字符串类型都派生自于Object类,String与StringBuffer和StringBuilder没有任何的承继关系,功能虽然有部分相似之处,但属于完全不同的表现形势,甚至他们之间没有重载 = 运算符,只能通过构造,不能直接赋值。
StringBuffer和StringBuilder在功能上却区别不大,仅仅在于StringBuffer内部实现了线程同步机制,而StringBuilder没有。
为了更有较的说明Java中三种字符串类型,有必要提一下C/C++字符串。
在C语言中字符串是以一种特殊的字符数组形势出现的,如:char chs[] = "I am a string!"; 在内存排列方式上C语言字符串与字符数组完全一样,区别仅仅只是字符串在末尾自动添加了'\0'的结束标记。数组名即是一个指针指向字符串的第一个字符地址,可以通过这个指针移位改变字符串中所有的内容,但如果要加长字符串必须重新申请内存空间,缩短字符串也仅仅只是将'\0'结束标记前移,而多余的内存并不会自动释放,除非重新分配。
而在内存分配上还有另外一种形势,如:char *p = "I am a string!"; 这种方式的字符串存放于文字常量区,仅返回一个指针以便使用,无法改变指针指向处的任何内容。
C++延用了C语言的字符串规则并提供一个string的字符串封装类,string的原理是在内部封装了一个char* 指针成员,内部实现并且对外提供了相应的成员函数以便操作string对象。实现了自动加长的功能,但其原理也是在string内部对char*指针指向的内存做了重新分配。
MFC类库中提供CStringT等几种字符串类型,但基础也是在C语言标准字符串上做了更多功能的封装。
了解了以上内容后,再看Java字符串。虽然我们在Java的源文件中都无法看到指针,也就是说无法查看内存的分布情况,但根据C语言字符串在内存中的排列方式不难猜想出Java底层对字符串的封装形势为:在一块连续的内存空间中每一段bit(C/C++是8bit,Java是16bit)存放一个二进制数,在提取与储存时根据指定的字符集转换成字符。而在高级语言编码中通过该块内存地址头记录这块内存,通过指定条件结束字符串。
Java中的String可以通过 String str = "I am a string!";这种形势直接为String类型赋值,我们完全可以认为在String的内部封装了一个char*指针,用来记录字符串的地址头。就是说String保存的字符串可能是一个存在于文字常量区中的字符串。而文字常量区中的内容一但生成是不可以被修改的。虽然String可以通过String str = new String()的形势初始化,将字符串存放于堆空间中。但为了便于统一化操作Java中String形势的字符串规定,一但初始化就不可以修改其内容。
String仅提供读取查询操作,不提供任何写入操作,任何有可能改变字符串内容的操作可能性只有两种。1.重新分配了String代表的内存空间。 2.操作原有字符串返回一个新的字符串。
String类提供了多种方法。如:
构造:
public String(byte[] bytes) //字节数组初始化
public String(byte[] bytes, int offset, int length) //部分字节数组初始化
public String(char[] value) //字符数组初始化
public String(char[] value, int offset, int count) //部分字符数组初始化
public String(String original) //复制初始化,以及另两种字符串的转换初始化
public String(StringBuffer buffer)
public String(StringBuilder builder)
public static String valueOf(Object obj) //将一个其它类型转换为一个String,多种重载 8种基本类型包括数组全部适用。
String str = "I am a string!" //重载了对象到字符指针的 = 号运算符,可以被文字常量字符串初始化
查询:
public char charAt(int index) //获取对应下标索引的char字符
public boolean contains(CharSequence s) //检测当前String是否包含参数String
public boolean endsWith(String suffix, int toffset) //检测String尾是否为参数String
public boolean startsWith(String suffix, int toffset) //检测String头是否为参数String
public boolean equals(Object anObject) //比较两个String是否内容一样 重载方法
public boolean equalsIgnoreCase(String anotherString) //忽略大小字的比较
public boolean isEmpty() //检测是否字符串为空,
public int compareTo(String anotherString) // 比较两个String的字典顺序
public int length() //长度获取
//查询一个子集在String中的位置
public int indexOf(int ch, int fromIndex)
public int indexOf(String str, int fromIndex)
public int lastIndexOf(int ch, int fromIndex)
public int lastindexOf(String str, int fromIndex)
操作:
//大小写转换
public String toUpperCase()
public String toLowerCase()
public String trim() //去除String两段的空格 这方法都有牛B透了。
public String concat(String str) //连接两个String返回一个连接后的String
public byte[] getBytes() //String转字节数组
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) //复制部分内容到字符数组
public String replace(char oldChar, char newChar) //使用指定字符替换原有指定String内字符,返回一个替换后的新String
public String[] split(String regex) //使用指定条件切割一个String,返回一个String数组,包括""空字符串。
public String substring(int beginIndex, int endIndex) //通过下标获取此String中的一部分
public char[] toCharArray() //String到字符数组的转换
StringBuffer与StringBuilder才是Java中真正的字符串类型变量。
两者的区别仅在于前者是内置同步。功能用法,甚至成员完全一致。
StringBuffer与StringBuilder可以看做是String的另一层封装,StringBuffer与StringBuilder遵守Java中所有对象必须堆中创建的规则,所以StringBuffer与StringBuilder必需new出来且只能由String初始化,当然也可以使用如下方式初始化:
StringBuilder strBuild = new StringBuilder("Java StringBuilder!");
String重载了到常量字符串的 = 号运算符。以上方式只是隐匿构造了一个String传递进去。
通过这些分析不难得出一个结论:Java中的String类似于C语言中的字符串,而StringBuffer与StringBuilder才类似于C++中的string。
StringBuffer与StringBuilder提供了String中部分的字符串查询和操作功能外,还提供了一些写入功能。
//多种重载,添加一个元素到末尾处,非String时将会通过调用toString转换后添加
public StringBuilder append(Object obj)
//多种重载,插入一个元素到指定位,非String时将会通过调用toString转换后插入
public StringBuilder insert(int offset, Object obj)
//删除,返回修改后的对象
public StringBuilder delete(int start, int end)
public StringBuilder deleteCharAt(int index)
//反转
public StringBuilder reverse()
//设置单个下标索引处的值
public void setCharAt(int index, char ch)
//设置长度,不足追加null补。
public void setLength(int newLength)
//修整多余内存占用,即结束标记后的多余空间
public void trimToSize()
结论:对于字符串的修改可能根据线程情况使用StringBuffer与StringBuilder。但对于字符串的查询,转换,检测等使用提供了更多此类方法String更方便。
Java中所有字符串均不是以'\0'做为结尾的,长度控制可能由对象的length成员标记,或是底层有其它转换方式。经测试在一个Java字符串中间加入一个'\0'时,字符串完整的被输出,'\0'的位置以一个空字节代替了。