黑马程序员技术交流社区

标题: 一个有些疑问的问题与大家交流(有一定的难度)! [打印本页]

作者: Union    时间: 2014-4-28 23:23
标题: 一个有些疑问的问题与大家交流(有一定的难度)!
本帖最后由 Union 于 2014-4-28 23:24 编辑

下面的程序将打印一个单词,其第一个字母是由一个随机数生成器来选择的。该程序:
  1. import java.util.Random;
  2. public class Rhymes {
  3.     private static Random rnd = new Random();
  4.     public static void main(String[]args) {
  5.         StringBuffer word = null;
  6.         switch(rnd.nextInt(2)) {
  7.             case 1:  word = new StringBuffer('P');
  8.             case 2:  word = new StringBuffer('G');
  9.             default: word = new StringBuffer('M');
  10. }
  11. word.append('a');
  12. word.append('i');
  13. word.append('n');
  14. System.out.println(word);
  15.     }
  16. }
复制代码

乍一看,这个程序可能会在一次又一次的运行中,以相等的概率打印出 Pain,
Gain 或 Main。看起来该程序会根据随机数生成器所选取的值来选择单词的第一
个字母:0 选 M,1 选 P,2 选 G。谜题的题目也许已经给你提供了线索,它实际
上既不会打印 Pain, 也不会打印 Gain。 也许更令人吃惊的是,它也不会打印 Main,
并且它的行为不会在一次又一次的运行中发生变化,它总是在打印 ain。

这是为什么?


欢迎解答!




作者: 谢振宣    时间: 2014-4-29 00:59
  1. /*
  2. import java.util.Random;
  3. public class Rhymes
  4. {
  5.     private static Random rnd = new Random();
  6.     public static void main(String[]args)
  7.         {
  8.         StringBuffer word = null;
  9.         switch(rnd.nextInt(2))//此处应是3,生成的随机数是0和指定值之间的数,不包括指定值
  10.                 {
  11.             case 1:  word = new StringBuffer('P'); //此处应传入字符串而不是字符,而且缺少break;否则只赋值最后一个
  12.             case 2:  word = new StringBuffer('G'); //至于为什么传入错误的数据类型可以成功创建对象,不太清楚
  13.             default: word = new StringBuffer('M');
  14.                 }
  15.                 word.append('a');
  16.                 word.append('i');
  17.                 word.append('n');
  18.                 System.out.println(word);
  19.     }
  20. }
  21. */

  22. //下面对原代码做了一下改善,结果是成功的

  23. import java.util.Random;
  24. public class Demo
  25. {
  26.         private static Random rnd = new Random();
  27.         public static void main(String[]args)
  28.         {
  29.                 for (int i=1;i<20;i++ )
  30.                 {
  31.                         StringBuffer word = null;
  32.                         switch(rnd.nextInt(3))
  33.                         {
  34.                                 case 0:  word = new StringBuffer("P"); break;
  35.                                 case 1:  word = new StringBuffer("G"); break;
  36.                                 default: word = new StringBuffer("M");
  37.                         }
  38.                         word.append('a');
  39.                         word.append('i');
  40.                         word.append('n');
  41.                         System.out.println(word);
  42.                 }
  43.         }
  44. }
复制代码

作者: 雪拉比    时间: 2014-4-29 11:51
学习了,小细节很重要
作者: 谢振宣    时间: 2014-4-29 13:40
谢振宣 发表于 2014-4-29 00:59

对于给StringBuffer传入字符可以成功创建对象的原因知道了。
StringBuffer中有一个构造函数StringBuffer(int capacity),
用于构造一个不带字符,但具有指定初始容量的字符串缓冲区。
传入的char类型的字符,被自动转换成了int类型,用于指定字符串缓冲区的初始容量。
作者: 土突突    时间: 2014-4-29 14:49
查了下帮助文档,发现StringBuffe的构造函数有
[size=+2]构造方法摘要
StringBuffer()
          构造一个其中不带字符的字符串缓冲区,初始容量为 16 个字符。
StringBuffer(CharSequence seq)
          public java.lang.StringBuilder(CharSequence seq) 构造一个字符串缓冲区,它包含与指定的 CharSequence 相同的字符。
StringBuffer(int capacity)
          构造一个不带字符,但具有指定初始容量的字符串缓冲区。
StringBuffer(String str)
          构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容

并没有StringBuffer(char ch)类型的构造函数,所以在new StringBuffer('P')时,会把字符自动转换为int类型的。即调用StringBuffer(int capacity)。此构造函数作用是“构造一个不带字符,但具有指定初始容量的字符串缓冲区。”所以在switch循环后,word里面仍然没有字符。故会一直打印ain
还有一点,rnd.nextInt(2)只会出现0或1,故应该把case(2)换为case(1)。并在case子句里加上break关键字。在new对象的时候参数应该是字符串而不是字符。


作者: 875588381    时间: 2014-4-29 15:00
2L正解。
首先是随机数的问题,nextInt(n),会产生0至n-1的随机整数。例如nextInt(2),只会产生0,1这两个整数。
其次是new StringBuffer的问题。new String('P'),在StringBuffer的构造函数中,没有接受单个字符的构造方法。但是有一个int型的参数,用于指定底层StringBuilder缓冲区大小的,
所以程序中实际上创建的是一个指定了capacity大小的StringBuffer对象,没有具体的内容。
最后就是case穿透的问题了,在case中没有break,就会一直执行到末尾的default语句上。

回答的貌似有些晚了,就当是总结吧,嘿嘿。
作者: Union    时间: 2014-4-29 19:49
谢振宣 发表于 2014-4-29 13:40
对于给StringBuffer传入字符可以成功创建对象的原因知道了。
StringBuffer中有一个构造函数StringBuffer( ...

回答的不错啊!
作者: Union    时间: 2014-4-29 19:50
土突突 发表于 2014-4-29 14:49
查了下帮助文档,发现StringBuffe的构造函数有

回答的挺对的!
作者: 王震阳老师    时间: 2014-4-29 20:56
  1. StringBuffer word = new StringBuffer('h');
  2.                 System.out.println('h'+0);
  3.                 System.out.println(word.capacity());
复制代码


如果你传入的字符而不是字符串的时候,那么你要知道StringBuffer有一个构造函数是StringBuffer(int capacity),那么Java会自动将字符‘h’转化为int型,在这里也就是104,所以你打印出来的总是ain。
作者: 张旭峰    时间: 2014-4-29 22:36
嘿嘿,这个程序有点意思啊,考验小细节,学习了。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2