万隆的笔记 万隆的笔记
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
  • 基础篇(上)

    • HelloWorld
    • 关键字、标识符和注释
    • 常量和进制的运算
    • 变量和类型转换
    • 基本数据类型运算细节
      • 字符类型运算细节
      • 整型运算细节
    • 运算符
  • 进阶

  • Java基础
  • 基础篇(上)
2022-02-09
目录

基本数据类型运算细节

# 基本数据类型运算细节

# 字符类型运算细节

先看一个字符类型与数字之间的运算示例的输出结果(ps: 实际编码的时候,行尾尽量不要使用注释):

// 运行结果:a
System.out.println('a'); 
// 运行结果:98
System.out.println('a' + 1);

从运行结果可知,字符类型在与数字运算时候,被转换为了数值(类型提升),也就是说字符和整型能够进行类型提升和强制转换。根本的原理式因为字符类型背后有个码表,而Java使用的Unicode码表。我们看看常见的编码表:

# ASCII

我们知道计算机内部所有信息最终都是一个二进制值。为了让进制数值与生活中文字字符有个间接关系,在上个世纪60年代,美国制定了一套字符编码,统一规定了英语字符与二进制位之间的关系,这套编码称为 ASCII 码,一直沿用至今。

ASCII码表是兼容很强的码表,它一共规定了128个字符的编码,它包含了常见的字母、数字、还有一些特殊符号。它用一个字节表示一个字母,但只占用了一个字节的后面7位(最前面的位统一规定为0),所以它只规定了128个字符而不是256个。常见的比如空格对应的码值是32,大写的字母A是65,小写的字母a是97。

# Unicode与UTF-8

如果要表示中文,显然一个字节是不够的,至少需要两个字节,而且还不能和ASCII编码冲突,所以,中国制定了GB2312编码,用来把中文编进去。类似的,日文和韩文等其他语言也有这个问题。为了统一所有文字的编码,Unicode(统一的字符编码标准)应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。 也就是说Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。

要注意的是Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。UTF-8 (opens new window)、UTF-16 (opens new window)、UTF-32 (opens new window)都是Unicode的实现(数字转换到程序数据的编码方案),目前在互联网上使用地最广的是UTF-8编码,它是针对Unicode的一种可变长度字符编码方式,它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。UTF-8 的编码规则很简单,只有二条:

  1. 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
  2. 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

# 整型运算细节

下面两段代码的编译结果会是什么?并说出理由。

// 第一段:
byte b = 0;
b = 1 + 1;
System.out.println(b);
// 第二段:
byte b = 0;
byte b1 = 1;
byte b2 = 1;
b = b1 + b2;
System.out.println(b);

第一段代码编译通过,输出结果为 2;第二段代码会编译失败:不兼容的类型,( b = b1 + b2)从int转换到byte可能会有损失。

这是因为Java默认的整数数据类型是int,编译认为0、1这种确定的数值的数据类型为int,在编译的时候,会判断int类型的0、1是否在byte类型的数值范围内,在的话就会强转,也就说编译器会进行阈值判断强转。

当定义表达式赋值符号(=)右边是一个确定的数值时候,可以进行阈值判断,从而进行强转。所以类似 b = 0,b = 1+ 1是可以通过编译的。但是当右边是变量时候,编译器无法对这些变量的值进行有效的判断,从而承担不必要的精度损失,即使它们的值之和不超过范围,所以编译会失败。

我们再讨论一下第二段代码,如果将第二段代码改成如下的情况,那么编译结果又会是什么结果呢?

int x = 0;
int x1 = 1;
int x2 = 1;
x = x1 + x2;
System.out.println(x);

结果就是编译通过,运行结果为2。这是因为对于赋值只要是整数类型,编译器便不会去进行阈值判断强转,认为这是个有效的表达式。也许会有人疑惑,如果表达式计算结果超出整类型数值范围会怎样?

int x1 = Integer.MAX_VALUE;
System.out.println(x);
int x2 = 1;
x = x1 + x2;
System.out.println(x);
/**
 * 2147483647
 * -2147483648
 */

由输出结果可以知道,如果两个整型变量相加超过了整型的阈值,java会对越界的数据进行默认的底层转换处理,将高位去掉,这时便变成负数。

参考:

ASCII,Unicode和UTF-8终于找到一个能完全搞清楚的文章了 (opens new window)

ascii码字节数目总结 (opens new window)

百度百科-Unicode (opens new window)

上次更新: 5/28/2023, 10:57:53 PM
运算符

运算符→

最近更新
01
2025
01-15
02
Elasticsearch面试题
07-17
03
Elasticsearch进阶
07-16
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式