故事背景

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

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

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 931E Game with String

    Game with String 题意:有一个字符串,可以选择从第K位开始,将[K,len(s)-1]的字符都移到前面去,现在给你一个首字母,你可以再选择一位进行观察,然后猜测这个K的值是多少, 现在 ...

  2. CodeForces 1018B The hat

    The hat 题解: 定义d[i]为第i个数和他对面的差值. 然后我们可以发现d[i]和d[i+1]的差值只会有3种情况2, -2, 0. 并且可以知道 d[i] = - d[i+n/2] 所以如果 ...

  3. Atcoder D - Widespread (二分)

    题目链接:http://abc063.contest.atcoder.jp/tasks/arc075_b 题解:直接二分答案然后再判断(a-b)来替代不足的.看代码比较好理解,水题. #include ...

  4. Springboot源码分析之代理对象内嵌调用

    摘要: 关于这个话题可能最多的是@Async和@Transactional一起混用,我先解释一下什么是代理对象内嵌调用,指的是一个代理方法调用了同类的另一个代理方法.首先在这儿我要声明事务直接的嵌套调 ...

  5. NameNode数据存储

    HDFS架构图 HDFS原理 1)  三大组件 NameNode. DataNode .SecondaryNameNode 2)NameNode 存储元数据(文件名.创建时间.大小.权限.文件与blo ...

  6. vue-property-decorator vue typescript写法

    什么是Typescript TypeScript 是一种由微软开发的自由和开源的编程语言,它是 JavaScript 的一个超集,扩展了 JavaScript 的语法.作者是安德斯大爷, Delphi ...

  7. Python中使用高德API实现经纬度转地名

    场景 高德API提供给开发者们一些常用功能的接口,其中有一种叫地理/逆地理编码能实现 地名查询经纬度和经纬度查地名. 实现 高德API平台: https://lbs.amap.com/ 注册并登陆 找 ...

  8. Java中各种引用(Reference)解析

    目录 1,引用类型 2, FinalReference 2.1, Finalizer 3, SoftReference 4, WeakReference 5, PhantomReference 6, ...

  9. php装上sqlserver驱动后仍然显示Call to undefined function sqlsrv_connect()问题

    今天老师要求本来的php+mysql改为php+sqlserver,在网上搜索了相应的教程,说是“需要下载安装Microsoft Drivers for PHP for SQL Server驱动”,下 ...

  10. TestNG(八) 类分组测试

    package com.course.testng.groups; import org.testng.annotations.Test; @Test(groups = "stu" ...