第一题:借助JDK, 选取几个String与StringBuffer 、StringBuilder的常用API,并编写实例测试API的功能。
-
public char charAt(int index)
该方法返回字符串中指定位置的字符,index的范围是0到length()-1。package string; public class Str { public static void main(String[]str){ String s = new String("String"); System.out.println(s.charAt(1)); // return t StringBuffer sb = new StringBuffer("StringBuffer"); System.out.println(sb.charAt(2)); // return r StringBuilder ss = new StringBuilder("StringBuffer"); System.out.println(ss.charAt(3)); // return i } }
-
public int indexOf(String str)
该方法接收一个String对象参数并返回该第一次出现该对象的下标,若参数不在对象中则返回-1。package string; public class Str { public static void main(String[]str){ String s = new String("String"); System.out.println(s.indexOf("ing")); // return 3 StringBuffer sb = new StringBuffer("StringBuffer"); System.out.println(sb.indexOf("Buffer")); // return 6 System.out.println(sb.indexOf("buffer")); // return -1 StringBuilder ss = new StringBuilder("StringBuffer"); System.out.println(ss.indexOf("Buffer")); // return 6 System.out.println(ss.indexOf("buffer")); // return -1 } }
-
substring
方法
用法为:public String substring(int beginIndex)
与
public String substring(int beginIndex, int endIndex)
两种
第一种用法接收一个数字,取从beginIndex开始到该字符串结尾的子字符串;第二种用法接收两个数字,取从beginIndex开始到endIndex结尾的子字符串,不包括下标为endIndex的字符。
示例如下:package string; public class Str { public static void main(String[]str){ String s = new String("String"); System.out.println(s.substring(0,3)); // return Str System.out.println(s.substring(2)); // return ring, equal to s.subtring(2,length) StringBuffer sb = new StringBuffer("StringBuffer"); System.out.println(sb.substring(0,3)); // return Str StringBuilder ss = new StringBuilder("StringBuffer"); System.out.println(ss.substring(0,3)); // return Str } }
第二题:请简述String,StringBuffer,StringBuilder三者之间的共同点与区别,应该分别在何种场景下使用?
共同点:
- 都是字符数组的封装,有许多与字符串相关的方法,使用起来非常方便;
- 可以自动检测数组越界等异常情况,可以动态分配字符数组内存;
区别:
String
对象的内容是不可变的,对String
对象的更改操作会建立一个新的对象,原有的对象不会发生变化;而StringBuffer
和StringBuilder
里面的内容都是可变的,对其内容的操作会在原有对象基础上进行;- 性能方面,由于
String
对象是不可变的,在两个String
对象进行字符串连接(使用“+”符号)时会新建String
对象,导致运行速度变慢,而StringBuffer
与StringBuilder
对象则可以通过append
方法进行字符串连接,无需建立新对象,性能更快; - 此外,
StringBuffer
是thread-safe
的,因为其含有方法是被synchronized
修饰的,具有原子性,而StringBuilder
不是thread-safe
,StringBuilder
的方法没有被synchronized
修饰。
第三题:为什么不建议在for循环中使用“+”进行字符串拼接?
1首先介绍一下使用“+”进行字符串拼接会发生什么事
请注意,“+”符号只适用于String
对象,该操作符无法对StringBuffer
或StringBuilder
对象进行拼接。
请看以下例子:
String s = "ABC";
s = s + "dd";
在上面的例子中,我定义了一个String
对象s
,其内容是"ABC",然后使用操作符“+”将s
与字符串"dd"进行拼接,在这个过程中发生了以下几件事:
- 首先将
String
对象s
转化为StringBuilder
对象(确实是StringBuilder
,而不是StringBuffer
,不信可以去debug
看看,我认为之所以用StringBuilder
是因为它比StringBuffer
效率更高),这里调用的是StringBuilder(String str)
构造方法,此时s
的内容是"ABC"; - 然后会通过
StringBuilder
的append
方法将字符串"dd"加入到对象s
(s
是StringBuilder
对象)中,s
的内容是"ABCdd"; - 最后调用对象
s
(此时s仍然是StringBuilder
对象)的toString
方法将s
转成String
类型,然后将新的内容赋给对象引用s
(这里指的是String
类型的s
),但此时已经重新生成了一个String
对象(因为String
类型是不可变的),其内容是"ABCdd",而原来s
所指向的String
对象仍然存在,只是不与对象引用s所关联了;
总结一下,使用“+”进行字符串拼接的语句s = s + "dd";
可以分为以下3个步骤:
StringBuilder stmp = new StringBuilder(s);
stmp.append("dd");
s = stmp.toString();
2 为什么不建议在for循环中使用“+”进行字符串拼接?
回到正题,前面探讨了使用“+”进行字符串拼接所发生的事情,那么这个问题就很容易解释了。
在使用“+”进行字符串串接的时候,会首先生成一个StringBuilder
对象,然后将后面的字符串加入StringBuilder
对象,最后返回String
类型时会生成一个String
对象,因此一个串接过程生成了2个对象,如果在循环里面使用这种方式进行串接,会生成非常多的对象,导致性能极差!因此在对多个字符串进行串接时最好使用StringBuilder
或StringBuffer的append
方法。
第四题:什么是字符串的编码与解码?请举例说明。
Java中采用的字符集是Unicode
字符集,因此对于Java来说,将Unicode
字符集转为本地字符集(即自己电脑上的字符集,如GB2312
或GBK
)的过程称为编码;将本地字符集转为Unicode
字符集的过程称为解码。
对于字符集编码方式的解读,可以看ASCII,Unicode和UTF-8终于找到一个能完全搞清楚的文章了。
下面举例说明将“中文”二字从Unicode
字符集转为GB2312
和UTF-8
字符集:
package string;
import java.io.*;
public class CharCode {
public static void printByteArray(String msg, byte[] t) {
System.out.println(msg + "length is " + t.length + "****************"); // length是字节个数
for (int i = 0; i < t.length; i++) {
System.out.println(Integer.toHexString(t[i])); // toHexString是将数字转为16进制表示
}
}
public static void printCharArray(String msg, char[] c) {
System.out.println(msg + "length is " + c.length + "****************");
for (int i = 0; i < c.length; i++) {
System.out.println(Integer.toHexString(c[i]));
}
}
public static void main(String[] args){
try{
String str = "中文";
System.out.println(str);
printCharArray("unicode: ",str.toCharArray()); //unicode字符集中对"中文"二字的对应代码
printByteArray("unicode: ",str.getBytes());
byte[] b;
b = str.getBytes("UTF-8"); //编码:转为本地字符集GBK2312对应的代码
printByteArray("UTF-8: ",b);
b = str.getBytes("GB2312"); //编码:转为本地字符集GB2312对应的代码
printByteArray("GB2312: ",b);
}
catch(UnsupportedEncodingException e){
System.out.println("没有相应的字符集!"); }
}
}
输出如下:
中文
unicode: length is 2****************
4e2d
6587
unicode: length is 6****************
ffffffe4
ffffffb8
ffffffad
ffffffe6
ffffff96
ffffff87
UTF-8: length is 6****************
ffffffe4
ffffffb8
ffffffad
ffffffe6
ffffff96
ffffff87
GB2312: length is 4****************
ffffffd6
ffffffd0
ffffffce
ffffffc4
可以看到,“中”的Unicode
编码是4e2d(16进制数),“文”的Unicode
编码是6587(16进制),而它们在Unicode
和UTF-8
字符集中均占用3个字节(length是6),在GB2312
字符集中各占用2个字节(length是4)。