基本数据类型运算细节
# 基本数据类型运算细节
# 字符类型运算细节
先看一个字符类型与数字之间的运算示例的输出结果(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 的编码规则很简单,只有二条:
- 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
- 对于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)