JAVA面试题解惑系列(六)——字符串(String)杂谈

JAVA面试题解惑系列(六)——字符串(String)杂谈


上一次我们已经一起回顾了面试题中常考的到底创建了几个String对象的相关知识,这一次我们以几个常见面试题为引子,来回顾一下String对象相关的其它一些方面。 

String的length()方法和数组的length属性 

String类有length()方法吗?数组有length()方法吗? 

String类当然有length()方法了,看看String类的源码就知道了,这是这个方法的定义: 
Java代码 复制代码
  1. public int length() {   
  2.     return count;   
  3. }  
[java] view plaincopy
  1. public int length() {  
  2.     return count;  
  3. }  

String的长度实际上就是它的属性--char型数组value的长度。数组是没有length()方法的,大家知道,在JAVA中,数组也被作为对象来处理,它的方法都继承自Object类。数组有一个属性length,这也是它唯一的属性,对于所有类型的数组都是这样。 

中文汉字在char中的保存 

一个中文汉字能保存在一个char类型里吗? 

请看下面的例子: 
Java代码 复制代码
  1. public class ChineseTest {   
  2.     public static void main(String[] args) {   
  3.         // 将一个中文汉字赋值给一个char变量   
  4.         char a = '中';   
  5.         char b = '文';   
  6.         char c = '测';   
  7.         char d = '试';   
  8.         char e = '成';   
  9.         char f = '功';   
  10.         System.out.print(a);   
  11.         System.out.print(b);   
  12.         System.out.print(c);   
  13.         System.out.print(d);   
  14.         System.out.print(e);   
  15.         System.out.print(f);   
  16.     }   
  17. }  
[java] view plaincopy
  1. public class ChineseTest {  
  2.     public static void main(String[] args) {  
  3.         // 将一个中文汉字赋值给一个char变量  
  4.         char a = '中';  
  5.         char b = '文';  
  6.         char c = '测';  
  7.         char d = '试';  
  8.         char e = '成';  
  9.         char f = '功';  
  10.         System.out.print(a);  
  11.         System.out.print(b);  
  12.         System.out.print(c);  
  13.         System.out.print(d);  
  14.         System.out.print(e);  
  15.         System.out.print(f);  
  16.     }  
  17. }  

编译没有报错,运行结果: 
  1. 中文测试成功


答案就不用说了。为什么一个中文汉字可以保存在一个char变量里呢?因为在JAVA中,一个char是2个字节(byte),而一个中文汉字是一个字符,也是2个字节。而英文字母都是一个字节的,因此它也能保存到一个byte里,一个中文汉字却不能。请看:

Java代码 复制代码
  1. public class ChineseTest {   
  2.     public static void main(String[] args) {   
  3.         // 将一个英文字母赋值给一个byte变量   
  4.         byte a = 'a';   
  5.         // 将一个中文汉字赋值给一个byte变量时,编译会报错   
  6.         // byte b = '中';   
  7.   
  8.         System.out.println("byte a = " + a);   
  9.         // System.out.println("byte b = "+b);   
  10.     }   
  11. }  
[java] view plaincopy
  1. public class ChineseTest {  
  2.     public static void main(String[] args) {  
  3.         // 将一个英文字母赋值给一个byte变量  
  4.         byte a = 'a';  
  5.         // 将一个中文汉字赋值给一个byte变量时,编译会报错  
  6.         // byte b = '中';  
  7.   
  8.         System.out.println("byte a = " + a);  
  9.         // System.out.println("byte b = "+b);  
  10.     }  
  11. }  


运行结果:

  1. byte a = 97


正如大家所看到的那样,我们实际上是把字符'a'对应的ASCII码值赋值给了byte型变量a。 

让我们回过头来看看最初的例子,能不能将a、b、c、d、e、f拼接在一起一次输出呢?让我们试试看:

Java代码 复制代码
  1. public class ChineseTest {   
  2.     public static void main(String[] args) {   
  3.         // 将一个中文汉字赋值给一个char变量   
  4.         char a = '中';   
  5.         char b = '文';   
  6.         char c = '测';   
  7.         char d = '试';   
  8.         char e = '成';   
  9.         char f = '功';   
  10.         System.out.print(a + b + c + d + e + f);   
  11.     }   
  12. }  
[java] view plaincopy
  1. public class ChineseTest {  
  2.     public static void main(String[] args) {  
  3.         // 将一个中文汉字赋值给一个char变量  
  4.         char a = '中';  
  5.         char b = '文';  
  6.         char c = '测';  
  7.         char d = '试';  
  8.         char e = '成';  
  9.         char f = '功';  
  10.         System.out.print(a + b + c + d + e + f);  
  11.     }  
  12. }  


运行结果:

  • 156035


这显然不是我们想要的结果。只所以会这样是因为我们误用了“+”运算符,当它被用于字符串和字符串之间,或者字符串和其他类型变量之间时,它产生的效果是字符串的拼接;但当它被用于字符和字符之间时,效果等同于用于数字和数字之间,是一种算术运算。因此我们得到的“156035”是'中'、'文'、'测'、'试'、'成'、'功'这六个汉字分别对应的数值算术相加后的结果。 

字符串的反转输出 

这也是面试题中常考的一道。我们就以一个包含了全部26个英文字母,同时又具有完整含义的最短句子作为例子来完成解答。先来看一下这个句子: 

引用
A quick brown fox jumps over the lazy dog.(一只轻巧的棕色狐狸从那条懒狗身上跳了过去。)



最常用的方式就是反向取出每个位置的字符,然后依次将它们输出到控制台:

Java代码 复制代码
  1. public class StringReverse {   
  2.     public static void main(String[] args) {   
  3.         // 原始字符串   
  4.         String s = "A quick brown fox jumps over the lazy dog.";   
  5.         System.out.println("原始的字符串:" + s);   
  6.   
  7.         System.out.print("反转后字符串:");   
  8.         for (int i = s.length(); i > 0; i--) {   
  9.             System.out.print(s.charAt(i - 1));   
  10.         }   
  11.   
  12.         // 也可以转换成数组后再反转,不过有点多此一举   
  13.         char[] data = s.toCharArray();   
  14.         System.out.println();   
  15.         System.out.print("反转后字符串:");   
  16.         for (int i = data.length; i > 0; i--) {   
  17.             System.out.print(data[i - 1]);   
  18.         }   
  19.     }   
  20. }  
[java] view plaincopy
  1. public class StringReverse {  
  2.     public static void main(String[] args) {  
  3.         // 原始字符串  
  4.         String s = "A quick brown fox jumps over the lazy dog.";  
  5.         System.out.println("原始的字符串:" + s);  
  6.   
  7.         System.out.print("反转后字符串:");  
  8.         for (int i = s.length(); i > 0; i--) {  
  9.             System.out.print(s.charAt(i - 1));  
  10.         }  
  11.   
  12.         // 也可以转换成数组后再反转,不过有点多此一举  
  13.         char[] data = s.toCharArray();  
  14.         System.out.println();  
  15.         System.out.print("反转后字符串:");  
  16.         for (int i = data.length; i > 0; i--) {  
  17.             System.out.print(data[i - 1]);  
  18.         }  
  19.     }  
  20. }  


运行结果:

  1. 原始的字符串:A quick brown fox jumps over the lazy dog.
  2. 反转后字符串:.god yzal eht revo spmuj xof nworb kciuq A
  3. 反转后字符串:.god yzal eht revo spmuj xof nworb kciuq A


以上两种方式虽然常用,但却不是最简单的方式,更简单的是使用现有的方法:

Java代码 复制代码
  1. public class StringReverse {   
  2.     public static void main(String[] args) {   
  3.         // 原始字符串   
  4.         String s = "A quick brown fox jumps over the lazy dog.";   
  5.         System.out.println("原始的字符串:" + s);   
  6.   
  7.         System.out.print("反转后字符串:");   
  8.         StringBuffer buff = new StringBuffer(s);   
  9.         // java.lang.StringBuffer类的reverse()方法可以将字符串反转   
  10.         System.out.println(buff.reverse().toString());   
  11.     }   
  12. }  
[java] view plaincopy
  1. public class StringReverse {  
  2.     public static void main(String[] args) {  
  3.         // 原始字符串  
  4.         String s = "A quick brown fox jumps over the lazy dog.";  
  5.         System.out.println("原始的字符串:" + s);  
  6.   
  7.         System.out.print("反转后字符串:");  
  8.         StringBuffer buff = new StringBuffer(s);  
  9.         // java.lang.StringBuffer类的reverse()方法可以将字符串反转  
  10.         System.out.println(buff.reverse().toString());  
  11.     }  
  12. }  


运行结果:

  1. 原始的字符串:A quick brown fox jumps over the lazy dog.
  2. 反转后字符串:.god yzal eht revo spmuj xof nworb kciuq A



按字节截取含有中文汉字的字符串 

要求实现一个按字节截取字符串的方法,比如对于字符串"我ZWR爱JAVA",截取它的前四位字节应该是"我ZW",而不是"我ZWR",同时要保证不会出现截取了半个汉字的情况。 

英文字母和中文汉字在不同的编码格式下,所占用的字节数也是不同的,我们可以通过下面的例子来看看在一些常见的编码格式下,一个英文字母和一个中文汉字分别占用多少字节。

Java代码 复制代码
  1. import java.io.UnsupportedEncodingException;   
  2.   
  3. public class EncodeTest {   
  4.     /**  
  5.      * 打印字符串在指定编码下的字节数和编码名称到控制台  
  6.      *   
  7.      * @param s  
  8.      *            字符串  
  9.      * @param encodingName  
  10.      *            编码格式  
  11.      */  
  12.     public static void printByteLength(String s, String encodingName) {   
  13.         System.out.print("字节数:");   
  14.         try {   
  15.             System.out.print(s.getBytes(encodingName).length);   
  16.         } catch (UnsupportedEncodingException e) {   
  17.             e.printStackTrace();   
  18.         }   
  19.         System.out.println(";编码:" + encodingName);   
  20.     }   
  21.   
  22.     public static void main(String[] args) {   
  23.         String en = "A";   
  24.         String ch = "人";   
  25.   
  26.         // 计算一个英文字母在各种编码下的字节数   
  27.         System.out.println("英文字母:" + en);   
  28.         EncodeTest.printByteLength(en, "GB2312");   
  29.         EncodeTest.printByteLength(en, "GBK");   
  30.         EncodeTest.printByteLength(en, "GB18030");   
  31.         EncodeTest.printByteLength(en, "ISO-8859-1");   
  32.         EncodeTest.printByteLength(en, "UTF-8");   
  33.         EncodeTest.printByteLength(en, "UTF-16");   
  34.         EncodeTest.printByteLength(en, "UTF-16BE");   
  35.         EncodeTest.printByteLength(en, "UTF-16LE");   
  36.   
  37.         System.out.println();   
  38.   
  39.         // 计算一个中文汉字在各种编码下的字节数   
  40.         System.out.println("中文汉字:" + ch);   
  41.         EncodeTest.printByteLength(ch, "GB2312");   
  42.         EncodeTest.printByteLength(ch, "GBK");   
  43.         EncodeTest.printByteLength(ch, "GB18030");   
  44.         EncodeTest.printByteLength(ch, "ISO-8859-1");   
  45.         EncodeTest.printByteLength(ch, "UTF-8");   
  46.         EncodeTest.printByteLength(ch, "UTF-16");   
  47.         EncodeTest.printByteLength(ch, "UTF-16BE");   
  48.         EncodeTest.printByteLength(ch, "UTF-16LE");   
  49.     }   
  50. }  
[java] view plaincopy
  1. import java.io.UnsupportedEncodingException;  
  2.   
  3. public class EncodeTest {  
  4.     /** 
  5.      * 打印字符串在指定编码下的字节数和编码名称到控制台 
  6.      *  
  7.      * @param s 
  8.      *            字符串 
  9.      * @param encodingName 
  10.      *            编码格式 
  11.      */  
  12.     public static void printByteLength(String s, String encodingName) {  
  13.         System.out.print("字节数:");  
  14.         try {  
  15.             System.out.print(s.getBytes(encodingName).length);  
  16.         } catch (UnsupportedEncodingException e) {  
  17.             e.printStackTrace();  
  18.         }  
  19.         System.out.println(";编码:" + encodingName);  
  20.     }  
  21.   
  22.     public static void main(String[] args) {  
  23.         String en = "A";  
  24.         String ch = "人";  
  25.   
  26.         // 计算一个英文字母在各种编码下的字节数  
  27.         System.out.println("英文字母:" + en);  
  28.         EncodeTest.printByteLength(en, "GB2312");  
  29.         EncodeTest.printByteLength(en, "GBK");  
  30.         EncodeTest.printByteLength(en, "GB18030");  
  31.         EncodeTest.printByteLength(en, "ISO-8859-1");  
  32.         EncodeTest.printByteLength(en, "UTF-8");  
  33.         EncodeTest.printByteLength(en, "UTF-16");  
  34.         EncodeTest.printByteLength(en, "UTF-16BE");  
  35.         EncodeTest.printByteLength(en, "UTF-16LE");  
  36.   
  37.         System.out.println();  
  38.   
  39.         // 计算一个中文汉字在各种编码下的字节数  
  40.         System.out.println("中文汉字:" + ch);  
  41.         EncodeTest.printByteLength(ch, "GB2312");  
  42.         EncodeTest.printByteLength(ch, "GBK");  
  43.         EncodeTest.printByteLength(ch, "GB18030");  
  44.         EncodeTest.printByteLength(ch, "ISO-8859-1");  
  45.         EncodeTest.printByteLength(ch, "UTF-8");  
  46.         EncodeTest.printByteLength(ch, "UTF-16");  
  47.         EncodeTest.printByteLength(ch, "UTF-16BE");  
  48.         EncodeTest.printByteLength(ch, "UTF-16LE");  
  49.     }  
  50. }  


运行结果如下:

  1. 英文字母:A
  2. 字节数:1;编码:GB2312
  3. 字节数:1;编码:GBK
  4. 字节数:1;编码:GB18030
  5. 字节数:1;编码:ISO-8859-1
  6. 字节数:1;编码:UTF-8
  7. 字节数:4;编码:UTF-16
  8. 字节数:2;编码:UTF-16BE
  9. 字节数:2;编码:UTF-16LE
  10. 中文汉字:人
  11. 字节数:2;编码:GB2312
  12. 字节数:2;编码:GBK
  13. 字节数:2;编码:GB18030
  14. 字节数:1;编码:ISO-8859-1
  15. 字节数:3;编码:UTF-8
  16. 字节数:4;编码:UTF-16
  17. 字节数:2;编码:UTF-16BE
  18. 字节数:2;编码:UTF-16LE



UTF-16BE和UTF-16LE是UNICODE编码家族的两个成员。UNICODE标准定义了UTF-8、UTF-16、UTF-32三种编码格式,共有UTF-8、UTF-16、UTF-16BE、UTF-16LE、UTF-32、UTF-32BE、UTF-32LE七种编码方案。JAVA所采用的编码方案是UTF-16BE。从上例的运行结果中我们可以看出,GB2312、GBK、GB18030三种编码格式都可以满足题目的要求。下面我们就以GBK编码为例来进行解答。 

如果我们直接按照字节截取会出现什么情况呢?我们来测试一下:

Java代码 复制代码
  1. import java.io.UnsupportedEncodingException;      
  2.      
  3. public class CutString {      
  4.     public static void main(String[] args) throws UnsupportedEncodingException {      
  5.         String s = "我ZWR爱JAVA";      
  6.         // 获取GBK编码下的字节数据      
  7.         byte[] data = s.getBytes("GBK");      
  8.         byte[] tmp = new byte[6];      
  9.         // 将data数组的前六个字节拷贝到tmp数组中      
  10.         System.arraycopy(data, 0, tmp, 06);      
  11.         // 将截取到的前六个字节以字符串形式输出到控制台      
  12.         s = new String(tmp);      
  13.         System.out.println(s);      
  14.     }      
  15. }   
[java] view plaincopy
  1. import java.io.UnsupportedEncodingException;     
  2.     
  3. public class CutString {     
  4.     public static void main(String[] args) throws UnsupportedEncodingException {     
  5.         String s = "我ZWR爱JAVA";     
  6.         // 获取GBK编码下的字节数据     
  7.         byte[] data = s.getBytes("GBK");     
  8.         byte[] tmp = new byte[6];     
  9.         // 将data数组的前六个字节拷贝到tmp数组中     
  10.         System.arraycopy(data, 0, tmp, 06);     
  11.         // 将截取到的前六个字节以字符串形式输出到控制台     
  12.         s = new String(tmp);     
  13.         System.out.println(s);     
  14.     }     
  15. }   


输出结果:

  1. 我ZWR?


在截取前六个字节时,第二个汉字“爱”被截取了一半,导致它无法正常显示了,这样显然是有问题的。 

我们不能直接使用String类的substring(int beginIndex, int endIndex)方法,因为它是按字符截取的。'我'和'Z'都被作为一个字符来看待,length都是1。实际上我们只要能区分开中文汉字和英文字母,这个问题就迎刃而解了,而它们的区别就是,中文汉字是两个字节,英文字母是一个字节。

Java代码 复制代码
  1. import java.io.UnsupportedEncodingException;   
  2.   
  3. public class CutString {   
  4.   
  5.     /**  
  6.      * 判断是否是一个中文汉字  
  7.      *   
  8.      * @param c  
  9.      *            字符  
  10.      * @return true表示是中文汉字,false表示是英文字母  
  11.      * @throws UnsupportedEncodingException  
  12.      *             使用了JAVA不支持的编码格式  
  13.      */  
  14.     public static boolean isChineseChar(char c)   
  15.             throws UnsupportedEncodingException {   
  16.         // 如果字节数大于1,是汉字   
  17.         // 以这种方式区别英文字母和中文汉字并不是十分严谨,但在这个题目中,这样判断已经足够了   
  18.         return String.valueOf(c).getBytes("GBK").length > 1;   
  19.     }   
  20.   
  21.     /**  
  22.      * 按字节截取字符串  
  23.      *   
  24.      * @param orignal  
  25.      *            原始字符串  
  26.      * @param count  
  27.      *            截取位数  
  28.      * @return 截取后的字符串  
  29.      * @throws UnsupportedEncodingException  
  30.      *             使用了JAVA不支持的编码格式  
  31.      */  
  32.     public static String substring(String orignal, int count)   
  33.             throws UnsupportedEncodingException {   
  34.         // 原始字符不为null,也不是空字符串   
  35.         if (orignal != null && !"".equals(orignal)) {   
  36.             // 将原始字符串转换为GBK编码格式   
  37.             orignal = new String(orignal.getBytes(), "GBK");   
  38.             // 要截取的字节数大于0,且小于原始字符串的字节数   
  39.             if (count > 0 && count < orignal.getBytes("GBK").length) {   
  40.                 StringBuffer buff = new StringBuffer();   
  41.                 char c;   
  42.                 for (int i = 0; i < count; i++) {   
  43.                     // charAt(int index)也是按照字符来分解字符串的   
  44.                     c = orignal.charAt(i);   
  45.                     buff.append(c);   
  46.                     if (CutString.isChineseChar(c)) {   
  47.                         // 遇到中文汉字,截取字节总数减1   
  48.                         --count;   
  49.                     }   
  50.                 }   
  51.                 return buff.toString();   
  52.             }   
  53.         }   
  54.         return orignal;   
  55.     }   
  56.   
  57.     public static void main(String[] args) {   
  58.         // 原始字符串   
  59.         String s = "我ZWR爱JAVA";   
  60.         System.out.println("原始字符串:" + s);   
  61.         try {   
  62.             System.out.println("截取前1位:" + CutString.substring(s, 1));   
  63.             System.out.println("截取前2位:" + CutString.substring(s, 2));   
  64.             System.out.println("截取前4位:" + CutString.substring(s, 4));   
  65.             System.out.println("截取前6位:" + CutString.substring(s, 6));   
  66.         } catch (UnsupportedEncodingException e) {   
  67.             e.printStackTrace();   
  68.         }   
  69.     }   
  70. }  
[java] view plaincopy
  1. import java.io.UnsupportedEncodingException;  
  2.   
  3. public class CutString {  
  4.   
  5.     /** 
  6.      * 判断是否是一个中文汉字 
  7.      *  
  8.      * @param c 
  9.      *            字符 
  10.      * @return true表示是中文汉字,false表示是英文字母 
  11.      * @throws UnsupportedEncodingException 
  12.      *             使用了JAVA不支持的编码格式 
  13.      */  
  14.     public static boolean isChineseChar(char c)  
  15.             throws UnsupportedEncodingException {  
  16.         // 如果字节数大于1,是汉字  
  17.         // 以这种方式区别英文字母和中文汉字并不是十分严谨,但在这个题目中,这样判断已经足够了  
  18.         return String.valueOf(c).getBytes("GBK").length > 1;  
  19.     }  
  20.   
  21.     /** 
  22.      * 按字节截取字符串 
  23.      *  
  24.      * @param orignal 
  25.      *            原始字符串 
  26.      * @param count 
  27.      *            截取位数 
  28.      * @return 截取后的字符串 
  29.      * @throws UnsupportedEncodingException 
  30.      *             使用了JAVA不支持的编码格式 
  31.      */  
  32.     public static String substring(String orignal, int count)  
  33.             throws UnsupportedEncodingException {  
  34.         // 原始字符不为null,也不是空字符串  
  35.         if (orignal != null && !"".equals(orignal)) {  
  36.             // 将原始字符串转换为GBK编码格式  
  37.             orignal = new String(orignal.getBytes(), "GBK");  
  38.             // 要截取的字节数大于0,且小于原始字符串的字节数  
  39.             if (count > 0 && count < orignal.getBytes("GBK").length) {  
  40.                 StringBuffer buff = new StringBuffer();  
  41.                 char c;  
  42.                 for (int i = 0; i < count; i++) {  
  43.                     // charAt(int index)也是按照字符来分解字符串的  
  44.                     c = orignal.charAt(i);  
  45.                     buff.append(c);  
  46.                     if (CutString.isChineseChar(c)) {  
  47.                         // 遇到中文汉字,截取字节总数减1  
  48.                         --count;  
  49.                     }  
  50.                 }  
  51.                 return buff.toString();  
  52.             }  
  53.         }  
  54.         return orignal;  
  55.     }  
  56.   
  57.     public static void main(String[] args) {  
  58.         // 原始字符串  
  59.         String s = "我ZWR爱JAVA";  
  60.         System.out.println("原始字符串:" + s);  
  61.         try {  
  62.             System.out.println("截取前1位:" + CutString.substring(s, 1));  
  63.             System.out.println("截取前2位:" + CutString.substring(s, 2));  
  64.             System.out.println("截取前4位:" + CutString.substring(s, 4));  
  65.             System.out.println("截取前6位:" + CutString.substring(s, 6));  
  66.         } catch (UnsupportedEncodingException e) {  
  67.             e.printStackTrace();  
  68.         }  
  69.     }  
  70. }  


运行结果:

  1. 原始字符串:我ZWR爱JAVA
  2. 截取前1位:我
  3. 截取前2位:我
  4. 截取前4位:我ZW
  5. 截取前6位:我ZWR爱

转载:

 

作者:臧圩人(zangweiren) 
网址:http://zangweiren.javaeye.com

阅读更多
文章标签: java 面试题
个人分类: java面试题
上一篇JAVA面试题解惑系列(五)——传了值还是传了引用?
下一篇JAVA面试题解惑系列(七)——日期和时间的处理
想对作者说点什么? 我来说一句

JAVA面试题解惑系列合集

2018年01月07日 792KB 下载

java面试题解析困惑之二

2010年01月19日 41KB 下载

JAVA面试题解惑系列

2009年05月19日 34KB 下载

JAVA面试题解惑系列合集.pdf

2010年05月20日 774KB 下载

Java面试题解惑系列

2011年09月21日 507KB 下载

JAVA面试题解惑系列.rar

2012年11月25日 1.16MB 下载

面试\JAVA,JEE基础,面试题汇总

2010年06月15日 478KB 下载

Java面试题(最全,最新)

2010年06月15日 1.47MB 下载

没有更多推荐了,返回首页

关闭
关闭