《Java深入解析-透析Java本质的36个话题》笔记_第一章

# 《Java深入解析》透析Java本质的36个话题笔记

 

## 第1 章 基本概念1

### 话题1 开门见山——测试你的Java 水平 1

### 话题2 世外隐者——隐居深山的“关键字” 2

《Java深入解析-透析Java本质的36个话题》笔记_第一章

goto const是java中的关键字,不允许作为标识符使用

《Java深入解析-透析Java本质的36个话题》笔记_第一章

true,false,null 不是关键字,也不能用于标识符,是字面常量。

 

### 话题3 疑团满腹——标识符更深层的思考6

《Java深入解析-透析Java本质的36个话题》笔记_第一章

(1)标识符的定义常见规则:

《Java深入解析-透析Java本质的36个话题》笔记_第一章

重新定义:

《Java深入解析-透析Java本质的36个话题》笔记_第一章

使用Character的方法可以判断一个字符可不可以作为标识符使用

《Java深入解析-透析Java本质的36个话题》笔记_第一章

 

```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

《Java深入解析-透析Java本质的36个话题》笔记_第一章

(1)三种转义

《Java深入解析-透析Java本质的36个话题》笔记_第一章

下面的定义会报错

```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

《Java深入解析-透析Java本质的36个话题》笔记_第一章

(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

《Java深入解析-透析Java本质的36个话题》笔记_第一章

(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

《Java深入解析-透析Java本质的36个话题》笔记_第一章

(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取整。

《Java深入解析-透析Java本质的36个话题》笔记_第一章

浮点数精度问题的原因:

《Java深入解析-透析Java本质的36个话题》笔记_第一章

例如: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)最近舍入

《Java深入解析-透析Java本质的36个话题》笔记_第一章

 

### 话题8 龙虎争霸——基本for 循环与加强型for 循环的对比45

《Java深入解析-透析Java本质的36个话题》笔记_第一章

增强型for循环局限:

《Java深入解析-透析Java本质的36个话题》笔记_第一章

在访问集合类元素的时候很方便,不用迭代器iterator

右边变量必须是数组或Iterator类型

底层实现也是基本的for循环