故事背景

一座普普通通的小屋里,住着大头儿子、小头爸爸和围裙妈妈。在他们普普通通的生活中,总是响起充满欢乐的笑声。最温暖的家又成了他们每个人的爱的源泉。

《大头儿子和小头爸爸》是孩子居首(大头),妈妈居中,爸爸最末(小头);爸爸主外,妈妈主内(围裙),他们是中国现代家庭教育典型的缩影。

java中的大头儿子和小头爸爸

java中也有一对冤家对头,他们就是字符char和字符串String。来看看他们的表现吧:                                               

        System.out.println("h"+"i");
System.out.println('h'+'i');

会打印出什么呢?结果可能出乎你的意外:

hi
209

为什么会出现209这个结果呢?

编译器在计算常量表达式'h'+'i'时,是通过我们熟知的拓宽原始类型转换将两个具有字符型数值的操作数('h'和'i')提升为int 数值而实现的。从char 到int 的拓宽原始类型转换是将16 位的char 数值零扩展到32 位的int。对于'h',char 数值是104,而对于'i',char 数值是105,因此表达式'h'+'i'等价于int常量104 + 105,或209。

有三种方式避免出现char的连接问题。第一种最简单:

System.out.println("" + 'h' + 'i');

第二种:使用函数

System.out.printf("%c%c", 'h', 'i');
或者
System.out.println(String.format("%c%c", 'h','i'));

第三种,利用api拼装:

StringBuffer sb = new StringBuffer();
sb.append('h');
sb.append('i');
System.out.println(sb);

也会你会认为这比较简单,那我们就见识一个比较复杂点的吧!

    private static Random rnd = new Random();
public static void main(String[] args) {
StringBuffer word = null;
switch(rnd.nextInt(2)) {
case 1: word = new StringBuffer('P');
case 2: word = new StringBuffer('G');
default: word = new StringBuffer('M');
}
word.append('a');
word.append('i');
word.append('n');
System.out.println(word);
}

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

多个问题,纠结在一起导致了这个问题:

1.Random.nextInt(int)的规范描述道:“返回一个伪随机的、均等地分布在从0(包括)到指定的数值(不包括)之间的一个int 数值”[Java-API]。这意味着表达式rnd.nextInt(2)可能的取值只有0和1,Switch语句将永远也到不了case2 分支,这表示程序将永远不会打印Gain。nextInt 的参数应该是3 而不是2。

2. case中没有任何break 语句。不论switch 表达

式为何值,该程序都将执行其相对应的case 以及所有后续的case[JLS 14.11]。因此,尽管每一个case 都对变量word 赋了一个值,但是总是最后一个赋值胜出,覆盖了前面的赋值。最后一个赋值将总是最后一种情况(default),即new StringBuffer{'M'}。这表明该程序将总是打印Main,而从来不打印Pain或Gain。

3.在本例中,编译器会选择接受int 的构造器,通过拓宽原始类型转换把字符数值'M'转换为一个int 数值77[JLS 5.1.2]。换句话说,new StringBuffer('M')返回的是一个具有初始容量77 的空的字符串缓冲区。该程序余下的部分将字符a、i 和n 添加到了这个空字符串缓冲区中,并打印出该字符串缓冲区那总是ain 的内容。

修改如下:

    private static Random rnd = new Random();
public static void main(String[] args) {
System.out.println("PGM".charAt(rnd.nextInt(3)) + "ain");
}

参考资料

【1】java解惑

【2】https://baike.baidu.com/item/%E5%A4%A7%E5%A4%B4%E5%84%BF%E5%AD%90%E5%92%8C%E5%B0%8F%E5%A4%B4%E7%88%B8%E7%88%B8/2346537?fromtitle=%E5%A4%A7%E5%A4%B4%E5%84%BF%E5%AD%90%E5%B0%8F%E5%A4%B4%E7%88%B8%E7%88%B8&fromid=3076860&fr=aladdin

大头儿子和小头爸爸的战斗--java字符和字符串的更多相关文章

  1. java字符统计+字符串压缩

    要实习了.突然发现自己好像什么都不会,就去看看题吧.在网上看到一个字符串压缩的题.看了一眼,感觉用python很简单.一个for循环+字典就可以搞定. 但是呢,主要还是java.下面就用java来实现 ...

  2. Java 字符与字符串

    字符 // 定义字符 char c1 = 'a'; char c2 = '1'; char c3 = '中'; // 自动装箱 Character c = c1; // 自动拆箱 c1 = c; // ...

  3. java字符,字符串,数字之间的转换

    string 和int之间的转换 string转换成int  :Integer.valueOf("12") int转换成string : String.valueOf(12) ch ...

  4. 【JAVA编码专题】 JAVA字符编码系列三:Java应用中的编码问题

    这两天抽时间又总结/整理了一下各种编码的实际编码方式,和在Java应用中的使用情况,在这里记录下来以便日后参考. 为了构成一个完整的对文字编码的认识和深入把握,以便处理在Java开发过程中遇到的各种问 ...

  5. 关于JAVA字符编码:Unicode,ISO-8859-1,GBK,UTF-8编码及相互转换

    我们最初学习计算机的时候,都学过ASCII编码. 但是为了表示各种各样的语言,在计算机技术的发展过程中,逐渐出现了很多不同标准的编码格式, 重要的有Unicode.UTF.ISO-8859-1和中国人 ...

  6. 小伙子又乱码了吧-Java字符编码原理总结

    前提 配合前面阅读的I/O和NIO的资料,现在总结一下关于字符集和乱码问题的原理和解决方案.参考资料: 码表ASCII Unicode GBK UTF-8 字符编码笔记ASCII,Unicode和UT ...

  7. java字符编码详解

    引用自:http://blog.csdn.net/jerry_bj/article/details/5714745 GBK.GB2312.iso-8859-1之间的区别 GB2312,由中华人民共和国 ...

  8. JAVA字符编码三:Java应用中的编码问题

    第三篇:JAVA字符编码系列三:Java应用中的编码问题 这部分采用重用机制,引用一篇文章来完整本部分目标. 来源:  Eceel东西在线 问题研究--字符集编码  地址:http://china.e ...

  9. 【字符编码】Java字符编码详细解答及问题探讨

    一.前言 继上一篇写完字节编码内容后,现在分析在Java中各字符编码的问题,并且由这个问题,也引出了一个更有意思的问题,笔者也还没有找到这个问题的答案.也希望各位园友指点指点. 二.Java字符编码 ...

随机推荐

  1. CodeForces 758 D Ability To Convert

    Ability To Convert 题意:给你一个n进制的60位的数,但是由于Alexander只会写0->9,所以他就会用10来表示十而不是A(假设进制>10); 题解:模拟就好了,先 ...

  2. Linux命令分类

    系统信息arch 显示机器的处理器架构(1)uname -m 显示机器的处理器架构(2)uname -r 显示正在使用的内核版本dmidecode -q 显示硬件系统部件 - (SMBIOS / DM ...

  3. 在eclipse中引入mybatis和spring的约束文件

    eclipse中引入mybatis约束文件步骤: 首先: config的key值 http://mybatis.org/dtd/mybatis-3-config.dtd mapper的key值 htt ...

  4. java基础day2

    Java标识符命名规则: 标识符由字母,下划线“_”.美元符号$或数字组成/ 不能以数字开头 区分大小写 不能是关键字 “ 见名知意” 约定俗成的规则 类名:首字母大写变量名:除第一个单词外小写,其他 ...

  5. PHP 错误:Warning: Cannot modify header information - headers already sent by ...

    PHP初学者容易遇到的错误:Warning: Cannot modify header information - headers already sent by ...: 通常是由不正确使用 hea ...

  6. Kubernetes监控实践

    一.Kubernetes介绍 Kubernetes(K8s)是一个开源平台,能够有效简化应用管理.应用部署和应用扩展环节的手动操作流程,让用户更加灵活地部署管理云端应用. 作为可扩展的容错平台,K8s ...

  7. Sticks(剪枝+BFS)

    Problem Description George took sticks of the same length and cut them randomly until all parts beca ...

  8. centos php7 安装mysqli扩展心得

    在新配服务器时发现,php无法连接到mysql.通过phpinfo发现.根本没有显示mysqli的相关配置.经过一系列研究.总结了下.: 第一步: 在phpinfo里没有mysqli配置,原因是安装p ...

  9. 重学js之JavaScript 面向对象的程序设计(创建对象)

    注意: 本文章为 <重学js之JavaScript高级程序设计>系列第五章[JavaScript引用类型]. 关于<重学js之JavaScript高级程序设计>是重新回顾js基 ...

  10. asp.net配置全局应用程序类 巧妙达到定时生成静态页面

    //在项目里添加一个"全局应用程序类(Global Application Class)",在里面写这样的代码: public class Global : System.Web. ...