大头儿子和小头爸爸的战斗–java字符和字符串

故事背景

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

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

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

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

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

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

hi209

为什么会出现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。

  1. 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

Original: https://www.cnblogs.com/davidwang456/p/11655763.html
Author: 一天不进步,就是退步
Title: 大头儿子和小头爸爸的战斗–java字符和字符串

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/539137/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 面试官:你说你精通Redis,你看过持久化的配置吗?

    前边我们已经介绍了 Redis 五种数据类型的命令与 配置文件的基本配置,今天让我们从理论和配置两个层面来揭开 Redis持久化的神秘面纱。 所谓持久化可以简单理解为将内存中的数据…

    Java 2023年6月5日
    075
  • 【Java面试手册-基础篇】能否声明main()方法为private或protected,或者不用访问修饰符?

    答案是否定的,main()方法必须public,不能定义main()方法为private和protected,也不能不用访问修饰符。 这是为了能让JVM访问main()方法,如果不…

    Java 2023年6月8日
    080
  • java延时队列 示例

    /** * @desc: java 延时队列 思路:使&#x7528…

    Java 2023年5月29日
    080
  • linux安装docker以及可视化管理界面

    一、docker 安装 1.0、准备 确保yum是最新的 yum update 查看是否已安装docker列表 yum list installed | grep docker 1…

    Java 2023年6月5日
    079
  • react面试题

    react面试题 从项目的整体看用户的使用方式复杂不同身份的用户有不同的使用方式(比如普通用户和管理员)多个用户之间可以协作与服务器大量交互,或者使用了 WebSocket Vie…

    Java 2023年6月5日
    0103
  • mybatis本地缓存&分布式缓存干货分享

    前言:干货记录&#…

    Java 2023年6月5日
    0103
  • PDF转图片,拼接图片

    一、导入PDF处理的包 阿里云仓库搜索icepdf-core依赖,找到合适的版本,导入pom.xml文件。 二、PDF转图片存储 1、读取目标PDF文件; 2、创建Document…

    Java 2023年6月5日
    088
  • shiro身份认证流程

    Shiro身份认证流程 身份认证:身份认证主要验证用户的身份,即验证用户操作时是其本人操作的,一般通过验证用户唯一principals和credentials,其中principa…

    Java 2023年6月7日
    099
  • Java核心技术-Lambda

    lambda表达式就是一个代码块以及必须传入代码的变量规范。lambda表达式就是把一个代码块作为参数,放在参数列表里面进行传递,共这个方法使用。数学上带参数变量的表达式就成为la…

    Java 2023年6月5日
    073
  • mybatis学习笔记(二)for 实践

    mybatis基本应用 1 快速入门 myBatis官网地址:http://www.mybatis.org/mybatis-3/ 1.1 开发步骤 引入依赖 创建user表 编写U…

    Java 2023年6月5日
    095
  • Leetcode链表

    Leetcode链表 边学边刷的……慢慢写慢慢更 题干: 思路: 删除链表节点,就多了一个判断等值。 由于是单向链表,所以要删除节点时要找到目标节点的上一个…

    Java 2023年6月7日
    088
  • spring-gateway基于数据库 + nacos 的动态路由

    动态路由的实现方式多种多样,研究一下基于数据方式的动态路由。 1. 创建项目,并pom.xml文件引入如下依赖 <span class="code-snippet_…

    Java 2023年6月7日
    092
  • 浅尝Spring注解开发_简单理解BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor、ApplicationListener

    浅尝Spring注解开发,基于Spring 4.3.12分析BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor…

    Java 2023年6月5日
    073
  • 高并发组件了解

    消息队列 A服务和多个服务耦合,内部维护对多个服务发送数据的接口,那么这些接口如果有的挂了,有的不需要了,那么还得修改A内部的代码,如果使用MQ,A发送消息就好,不必考虑那么多事情…

    Java 2023年6月8日
    097
  • Java 基础【18】 反射与内省

    Java 反射机制(Reflect)容许程序在运行时加载、探知、使用编译期间完全未知的 class,核心类 java.lang.Class。 通过把指定类中各种元素映射成 java…

    Java 2023年5月29日
    056
  • redis

    Nosql概述 因为数据的访问量越来越大,单靠关系型数据库已经无法支撑用户需求,所以架构也在用户的需求下一步步进行演进。 1、单机Mysql时代 90年代,一个网站的访问量一般不会…

    Java 2023年6月9日
    075
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球