《Java深入解析-透析Java本质的36个话题》笔记_第一章
# 《Java深入解析》透析Java本质的36个话题笔记
## 第1 章 基本概念1
### 话题1 开门见山——测试你的Java 水平 1
### 话题2 世外隐者——隐居深山的“关键字” 2
goto const是java中的关键字,不允许作为标识符使用
true,false,null 不是关键字,也不能用于标识符,是字面常量。
### 话题3 疑团满腹——标识符更深层的思考6
(1)标识符的定义常见规则:
重新定义:
使用Character的方法可以判断一个字符可不可以作为标识符使用
```java
private static void valid() {
int startNum = 0;
int partNum = 0;
for(int i=0x0000;i<0x10ffff;i++) {
if(Character.isJavaIdentifierStart(i)) {
startNum++;
}
if(Character.isJavaIdentifierPart(i)) {
partNum++;
}
}
System.out.println("Unicode字符集个数:"+(0x10ffff+1));
System.out.println("可以作为标识符首的字符个数:"+startNum);
System.out.println("可以作为标识符一部分的字符个数:"+startNum);
System.out.println("差:"+(partNum-startNum));
}
输出:
Unicode字符集个数:1114112
可以作为标识符首的字符个数:101296
可以作为标识符一部分的字符个数:101296
差:2288
```
Unicode字符集范围0x0000-0x10ffff
标识符的字母不局限26个字母,包含了其他的Unicode字符,但只是Unicode字符集的一部分,
不能作为标识符首的字母也不只限0-9数字字符
(2)避免$符号命名标识符
避免使用$符号命名标识符,会出现意想不到的错误,$符号通常用于编译器生成的文件命名,可以查看class文件。
(3)标识符长度
java语言规范中标识符长度是任意的,但在Java虚拟机规范中是有长度限制的。在class文件中,标识符常量字符串存储在CONSTANT_Utf8_info表中,使用2个字节表示字符串长度,最大长度为65535(2^16-1),所以标识符最大长度也是65535,而且仅限于除了空字符null以外的ASCII字符(‘\u0001’-‘\u007f’),使用这个范围以外的字符,最大长度会减少。
### 话题4 鞭长莫及——我的特殊字符,你不能用!10
(1)三种转义
下面的定义会报错
```java
char c1 = '\u0027'; //转义之后为单引号,没有合理的匹配
char c2 = '\u005c'; ////转义之后为\,转义符后面要跟转义的字符
String string = "\u0022"; //转义之后为双引号,没有合理的匹配
char c3 = '\400'; // 八进制转义范围:0-255('\u0000'-'\u00ff'),'\400'的十进制表示256
char c4 = '\28'; // 八进制转义只能有0-7数字
```
(2) 回车换行不要使用Unicode转义
```java
char c4 = '\u000a';// 转义为换行
相当于在'后面键入换行符
char c4 = '
';
char c4 = '\u000b';// 转义为回车
相当于在'后面键入回车
char c4 = '
';
// 使用下面两种方式表示回车换行
char c1 = '\n';// 换行
char c2 = '\12';// 换行
char c3 = '\r';// 回车
char c4 = '\15';// 回车
```
(3)区别和联系
Unicode转义在编译器丢弃空白和注释之前就进行转换成其表示的字符,转义序列符和八进制转义的处理要晚。
(4)Unicode增补字符:超出原来的16位限制的字符
U+0000~U+10FFFF 为基本多语言面(BMP)
0x10000-0x10FFFF 为增补字符范围,增补字符使用两个代码单元(一个字符编码使用的最小存储单元)来编码,不能使用char类型常量表示,超出了65535范围。
如:\u10000 要表示为\ud800\udc00
第一个代码单元高代理范围(U+D800~U+DBFF),低代理范围(U+DC00~U+DFFF)
增补字符代理对的值区间为U+D800~U+DFFF,该区间没分配字符。
### 话题5 移星换斗——从byte b = 1 谈类型转换的神秘 16
(1)隐式转换
```java
private void int2Byte() {
// 这是特例,隐式转换
// (1)只使用于对变量类型是byte,short或char赋值的时候
// (2)赋值安全。对超过范围的转换会报错。
byte b = 1;
char c = 1;
short s = 1;
int i = 1;
// 下面的会报错
// byte b2 = i;
// char c2 = i;
// short s2 = i;
}
```
(2)整形转换
整形:byte,short,char,int,long
char无符号(0~65535),转byte和short都要显式类型转换。
byte,short,char运算结果为int类型。
“+=” 复合运算在赋值时会自动转换结果为左边操作数类型。
byte 转char 要扩展收缩转换:先byte类型扩展转int类型,再从int收缩成char类型。
如:byte值为10,补码
0000 1010
扩展为int类型,补码:
0000 0000 0000 0000 0000 0000 0000 1010
int收缩为char类型,补码:
0000 0000 0000 1010
结果还是10
byte值为-10,补码
1111 1010
扩展为int类型,补码:
1111 1111 1111 1111 1111 1111 1111 1010
int收缩为char类型,截取低16位,补码:
1111 1111 1111 1010
结果就不是10
整形之间的转换,有符号符号位扩展,无符号0扩展。大转小截断。
(3)整形转浮点
所有整形转浮点都是扩展转换,但跟整形之间的扩展转换不同,整形之间的扩展转换是精确的。
### 话题6 扑朔迷离——浮点类型的种种悬疑22
(1)避免浮点数比较
二进制能表示的相邻的浮点值之间存在间隙。
浮点值越大,间隙越大,跟存储方式有关。
当浮点值大到一定程度,对浮点值改变很小,不足以影响浮点值改变。
浮点数量级差别很大时,做加减运算可能无法得到预期的结果。
(2)整形转浮点
当int类型或long类型数值的有效数字多于float或double类型最大有效数字,一些最低有效位就会丢失。
丢失精度采用IEEE754最近舍入算法
(3)浮点转整形
NaN -> int,long 类型为0
+-Infinity(正负无穷) 或超过int或long取值范围,结果为int或long最大值
在int或long取值范围,向0取整
转byte,short,char,先转int再收缩
如:浮点数 -12345678.6 转byte
-12345678.6 转int向0取整-12345678,补码:
1111 1111 0100 0011 1001 1110 1011 0010
收缩转byte,截断低8位:
1011 0010
表示十进制78
收缩转char或short,截断低16位:
1001 1110 1011 0010
char是无符号的,十进制表示40626
short是有符号的,十进制表示-24910
### 话题7 水落石出——浮点结构的最终解密31
(1)存储格式
类型 符号位 指数域 有效位数域
float 1位(第31位) 8位(第23~30位) 23位(第0~22位)
double 1位(第63位) 11位(第52~62位) 52位(第0~51位)
符号位:0为正,1为负
指数域:偏移量方式存储,2^x-1(X为指数位数)
(2)根据指数位和有效位不同,分三类
a.正规化浮点数
当指数域不全为0并且不全为1,该浮点数就是正规化浮点数。
正规化浮点数的有效位数(小数部分)会在实际存储小数值的结果上加1。例如:float类型值99.5f的32位存储结构如下:
0 10000101 10001110000000000000000
二进制的有效位数为0.1000111,加1的二进制结果为1.1000111。而指数部分(133)减去偏移量(2^8-1=127)后的值为6,因此根据浮点值可以表示为v=s*m*2^e,99.5f就可以写成:
99.5f=1*1.1000111*2^6
b.非正规化浮点数
当指数域全为0并且有效位数域不全为0时,该浮点数就是非正规化浮点数。
需要注意的是,非正规化浮点数的指数值为1-偏移量。
例如,float类型值5.877472E-39f的32位存储结构如下:
0 00000000 10000000000000000000000
二进制的有效位数为0.1,实际上也就是这个值(不再加1),指数为1-偏移量,float类型的偏移量为127,即-126,因此该浮点数可以写成:
5.877472E-39f=1*0.1*2^(-126)
c.特殊浮点数
浮点数 符号位 指数域 有效位数域
0 0 全为0 全为0
-0 1 全为0 全为0
正无穷大 0 全为1 全为0
负无穷大 1 全为1 全为0
NaN 任意 全为1 不全为0
(3)近似存储
十进制小数部分转换二进制采用的是乘2取整。
浮点数精度问题的原因:
例如:0.3小数位乘积永远取不到1,就算double类型有52位有效位也不能准确存储。
(4)打印浮点数的二进制形式
int value = Float.floatToIntBits(f);
String s = Integer.toBinaryString(value);
(5)浮点数之间的间隙
浮点数间隙随着浮点值的绝对值增大而增大
```java
// ulp 返回下一个float(double)类型浮点值x与参数的间隙
System.out.println(Math.ulp(0.3f));
float f = 88.88f;
// 下面的用法等价
//nextUp 返回正无穷方向的下一个数值
System.out.println(Math.nextUp(f));
//nextAfter 可以指定方向
System.out.println(Math.nextAfter(f,Float.POSITIVE_INFINITY));//POSITIVE_INFINITY 正无穷
```
(5)浮点精度丢失问题
float值1.6777216E7
十六精致表示:
0x1.0p24
二进制表示:
1 0000 0000 0000 0000 0000 0000
加1:
1 0000 0000 0000 0000 0000 0001
float有效位数只有23位,所以第24位丢失
(6)最近舍入
### 话题8 龙虎争霸——基本for 循环与加强型for 循环的对比45
增强型for循环局限:
在访问集合类元素的时候很方便,不用迭代器iterator
右边变量必须是数组或Iterator类型
底层实现也是基本的for循环