Java是强类型的语言,这意味着必须为每一个变量声明类型,根据最新(Java SE 14 Edition),Java一共有两种类型数据类型:primitiveType, referenceType。<sup>[1]</sup>
## 基本概念
### 整型
类型 | 存储需求 | 取值范围 |
---|---|---|
byte | 1 byte | -128 ~ 127 ( -2<sup>^</sup>7 ~ 2<sup>^</sup>7-1) |
short | 2 bytes | -32 768 ~ 32 767 ( -2<sup>^</sup>15 ~ 2<sup>^</sup>15-1) |
int | 4 bytes | -2 147 483 648 ~ 2 147 483 647 ( -2<sup>^</sup>31 ~ 2<sup>^</sup>31-1 , 超过20亿) |
long | 8 bytes | -9 223 372 036 854 775 808 ~ 9 223 372 036 854 775 807 ( 超过90万兆 ) |
byte 和 short 主要用于特定的场合,如底层的文件处理或者需要控制占用存储空间量的大数组, 与C, C++不同, **Java整型的范围与运行Java代码的机器无关**,这就解决了Java语言跨平台的问题,不会存在在32位系统与64位系统内存溢出等问题,且Java没有任何无符号(unsigned)形式的int, long, byte, short。
### 浮点类型
类型 | 存储需求 | 取值范围 |
---|---|---|
float | 4 bytes | +- 3.402 823 47E+38F (有效位数 6~7 位) |
double | 8 bytes | +- 1.797 693 134 862 315 70E+308 (有效位数 15 位) |
具体的float, double取值方范围计算可以参考IEEE 754<sup>[2]</sup>,注意,浮点数不能用于无法接收舍入误差的金融计算中,因为二进制系统无法精确地表示分数 1/10, 如不允许舍入误差可以使用 **BigDecimal**
System.out.println(2.0 - 1.1) // 0.89999999999
### char
char 类型大小为 2 字节,可以用16进制表示, 范围为 \u0000 ~ \Uffff (共65536个)
**Unicode编码 与 char 类型**
在计算机的发展过程中,出现了很多编码方式,也是我们在开发过程中经常会遇到乱码问题的原因,简单整理出现过的编码类型如下表。
| 编码类型 | 字节数 | 国家/组织 | 时间 |
| :---------: | :----------------------------------------------------: | :----------------: | ------ |
| ASCII | 1 byte (标准ASCII码128个字符, 后128个为扩展ASCII码) | 美国 | 1967年 |
| GB2312-80 | 2 bytes | 中国 | 1980年 |
| GBK | 2 bytes | 中国 | 1995年 |
| ISO-8859-1 | 1 byte | ECMA | 1987年 |
| Unicode 1.0 | 2 bytes | Unicode Consortium | 1991年 |
这里具体介绍下Unicode, 在Unicode之前有很多编码标准,这就造成了两个问题:
- 对于任意给定的代码值,在不同的编码方案下有可能对应不同的字母
- 采用大字符集的语言其编码长度可能不同
设计Unicode编码规则的初衷就是解决以上两个问题,在20世纪80年度开始启动设计工作时,人们认为两个字节的代码宽度足以对世界上各种语言的所有字符进行编码,并可以给未来留下扩展空间,1991年发布的Unicode 1.0仅使用2个字节, 后来加入了大量的汉语、日语和韩语,很快 16 位的 char 类型已经不能满足需求了。
> 码点: 与一个编码表中的某个字符对应的代码值
> 代码级别(code plane):Unicode的代码级别可以分成17个代码级别:
> - 第一个代码界别成为基本的多语言级别(basic multilingual plane), 码点从U0000到UFFFF,其中包括京东的Unicode代码。
> - 其余的16个级别的码点从U+10000到U10FFFF, 其中包括一下辅助字符(supplementary character)
UTF-16编码采用了不同长度的编码标识所有的Unicode码点(code unit) 在基本的多语言级别汇中,每个字符用16位表示,通常被成为代码单元(code unit),而辅助字符采用一对连续的代码单元进行编码。
在Java 中, char类型描述了UTF-16编码的一个代码单元, 这里不建议在程序中使用 char 类型,除非确实需要处理UTF-16代码单元,最好将将字符串作为抽象数据类型处理。
可以使用Character 类中的 `isJavaidentifierStart` 和`isJavaIdentifierPart`来判断 java 是否支持该 Unicode 字符。
## 基本类型转换
![primitiveTypeCast.png](https://github.com/CornPrincess/Backend_Nodets/blob/master/asserts/JavaSE/primitiveTypeCast.png)
Java数值类型转换规则如上图,实线表示无京都损失,虚线表示存在精度损失,简单总结规则:
- 两数中存在一个double类型,则另一个会转换为double类型
- 两数中存在一个float类型,则另一个会转换为float类型
- 两数中存在一个long类型,则另一个会转换为long类型
- 否则,两个操作数转化为int类型
### 强制类型转换
关于数值类型的强制类型转换有几点注意点:
byte a = 1;
byte b = a + 1; // throw error
byte b = (byte) (a + 1); // rihgt
第二行代码会报错,原因在于:根据上面介绍的规则,对 b 进行赋值运算时右边式子的值会转化为 int 类型,此时需要 加上强制类型转换才行。
byte a = 1;
a += 1.0; // euqals to a = (byte) a + 1.0 --- a = 2
上述代码第二行不会报错,因为当二元运算符左边的类型与右边的类型不同时将会自动发生强制类型转换。
## Reference
1. [The Kinds of Types and Values](https://docs.oracle.com/javase/specs/jls/se14/html/jls-4.html#jls-4.1)
2. [IEEE 754](https://www.h-schmidt.net/FloatConverter/IEEE754.html)
3. [Java核心技术·卷 I(原书第10版)](https://book.douban.com/subject/26880667/)
来源:oschina
链接:https://my.oschina.net/u/4254857/blog/3217883