Java深入解析笔记

关键字与标识符

goto、const、true、false、null
goto是Java里的保留字(不使用的关键字),在java里使用标签实现跳转:

public class Test1{
    public static void main(String[] args) {
        int[][] arr = {
                {1,20,28},
                {26,50},
                {33,55,66,88}
        };
        int number = 0;
        outer:
        for (int i = 0;i < arr.length; i++ ) {
            for (int j = 0; j < arr[i].length ; j++) {
                System.out.println(arr[i][j]);
                number++;
                if (number == 5) {
                    break outer;//java里使用标签 替代goto
                }
            }
        }
    }
}

与goto类似,const也是保留字,而true、fasle、null不是关键字,但是却不能作为标识符使用!
标识符
组成标识符的字母不再局限于26个英文字母而是Unicode字符集(U+0000~U+10FFFF),可以使用Character类里的下列方法判断标识符的合法性:

//判断字符是否是合法的标识符首字符
public static boolean isJavaIdentifierStart(int codePoint)
//判断字符是否是合法的标识符字符
public static boolean isJavaIdentifierPart(int codePoint) 

//内部调用的是isJavaIdentifierStart(int codePoint)
public static boolean isJavaIdentifierStart(char ch)
//内部调用的是 isJavaIdentifierPart(int codePoint) 
public static boolean isJavaIdentifierPart(char ch)
public class Test2 {
    public static void main(String[] args) {
        int start = 0;
        int part = 0;
        //Unicode范围u+0000~u+10FFFF
        for (int i = 0x0000; i < 0x10ffff; i++) {
            if (Character.isJavaIdentifierStart(i)){
                start++;
            }
            if (Character.isJavaIdentifierPart(i)){
                part++;
            }
        }
        System.out.println("Unicode字符集个数:" + (0x10ffff + 1));
        System.out.println("可以作为标识符首字符的个数:" + start);
        System.out.println("可以作为标识符的一部分的个数:" + part);
        System.out.println("二者之差:" + (part - start));
    }
}

运行结果:

Unicode字符集个数:1114112
可以作为标识符首字符的个数:101296
可以作为标识符的一部分的个数:103584
二者之差:2288

Unicode最初设计是固定的16位字符编码,范围是U+0000 ~ U+FFFF被称为基本多语言面(BMP),java中使用char类型表示,随着Unicode的不断扩展,已经超出了这个范围,目前有效范围是U+0000 ~ U+10FFFF, 超出的部分U+10000 ~ U+10FFFF被称为增补字符,这部分不能用char来表示,而要使用代理对表示:

public class Test3 {
    public static void main(String[] args) {
      int codePoint = 0x28e16;
      //将 代码点 转换成字符数组,取得 代理对 编码值
        char[] chars = Character.toChars(codePoint);
        String s = String.valueOf(chars);
        System.out.println("增补字符为:" + s);
        System.out.println("String长度:" + s.length());
        System.out.println("String代码点的数量:" + s.codePointCount(0, s.length()));
        System.out.println("高代理字符编码值:U+" + Integer.toHexString(chars[0]));
        System.out.println("低代理字符编码值:U+" + Integer.toHexString(chars[1]));
        //通过代理对获得代码点
        int codePoint2 = Character.toCodePoint(chars[0], chars[1]);
        System.out.println("代码点:" + Integer.toHexString(codePoint2));
    }
}

运行结果:

增补字符为:?
String长度:2
String代码点的数量:1
高代理字符编码值:U+d863
低代理字符编码值:U+de16
代码点:28e16

表示“?”字,用'\u28e16'肯定不行,而要表示成"\ud863\ude16" 代理对的取值区间是U+D800 ~ U+DFFF,该区域没有分配字符。
Unicode转义处理时期是在编译器将程序解析成各种符号之前进行的,如果\u后面没有接4个十六进制数字,将会产生编译错误,就算是在注释中也不例外!
整型转换
byte类型到char类型转换比较特殊,称为扩展收缩转换,分为两个步骤:

  • 将byte通过扩展转换,转换成int类型
  • 再将int类型通过收缩转换,转换成char类型
public class Test5 {
    public static void main(String[] args) {
        byte b1 = 10;
        byte b2 = -10;
        char c1 = (char) b1;
        char c2 = (char) b2;
        System.out.println(c1 + 0);//转为int以便输出
        System.out.println(c2 + 0);
    }
}

运行结果:

10
65526

先分析byte值为10的转换,其二进制为0000 1010,计算机里存放的都是对应补码,正数的补码是其本身,其补码:

0000  1010

转换为char的第一个步骤,扩展为int类型,执行符号扩展,因为是正数,所以高位补0:

0000 0000 0000 0000 0000 0000 0000 1010

第二个步骤,将int收缩转换为char,直接截取低16位:

0000 0000 0000 1010

最终转为int输出0000 0000 0000 0000 0000 0000 0000 1010,其值还是10。
然后分析byte值为-10的转换过程,-10的原码1000 1010,其补码1111 0110(符号位不变其他取反,然后加1):
转换char的步骤一,byte转为int,执行符号扩展,高位补1(因为符号位是1)

1111 1111 1111 1111 1111 1111 1111 0110

步骤二,截取低16位:

1111 1111 1111 0110

最终换位int输出,因char是无符号类型,所以高位补0 0000 0000 0000 0000 1111 1111 1111 0110,其值为65526
注意:char是无符号类型,最高为依然是其有效数字而不是符号位!
浮点类型
二进制大多不能精确的表示小数,所以浮点数在计算机中只是近似存储,如:

   float f1 = 0.1f;
   float f2 = 0.2f;
   System.out.println(f1 + f2);
   //0.30000000149011613
for(float f = 0.1f; f != 1; f += 0.1f){
	...
}
//实际上是个死循环
 //如果数量级差别很大 计算会有偏差
 float f3 = 30000000;
 float f4 = f3 + 1;
 System.out.println("f3 = " + f3 + ", f4 = " + f4);
 System.out.println(f3 < f4);

 //f3 = 3.0E7, f4 = 3.0E7
 //false

浮点数与整形的转换
整形转浮点型虽然是扩展转换,但是如果其范围超出了浮点型的有效数字范围(float7 ~ 8个有效数字 double15 ~ 16个),就会采用IEEE754最近舍入模式,提取与该整型最接近的浮点值,就会有精度损失:

public class Test7 {
    public static void main(String[] args) {
        int a = 7654321;
        int b = 987654321;
        float a1 = a;
        float b1 = b;
        System.out.println(a1);
        System.out.println(b1);
    }
}
7654321.0
9.8765434E8
目录 目 录 第1章 基本概念 1 话题1 开门见山——测试你的Java水平 1 话题2 世外隐者——隐居深山的“关键字” 2 话题3 疑团满腹——标识符更深层的思考 6 话题4 鞭长莫及——我的特殊字符,你不能用! 10 话题5 移星换斗——从byte b = 1谈类型转换的神秘 16 话题6 扑朔迷离——浮点类型的种种悬疑 22 话题7 水落石出——浮点结构的最终解密 31 话题8 龙虎争霸——基本for循环与加强型for 循环的对比 45 第2章 运算符与表达式 52 话题9 莫衷一是——i+++j该如何计算? 52 话题10 千差万别——++i与i++仅是“先加”与“后加”的差别吗? 56 话题11 强大相径庭——相除与求余在Java中的具体表现 61 话题12 移形换位——移位运算的真实剖析 75 话题13 鞭辟近里——条件运算符(?:)的类型深入 81 话题14 井然有序——运算顺序的详细挖掘 86 话题15 异曲同工——交换变量的3种方式 90 话题16 择木而栖——开关选择表达式switch的类型内幕 95 第3章 String类 103 话题17 来龙去脉——“+”是怎样连接字符串的? 103 话题18 一成不变——不可修改的String对象 107 话题19 钩深索隐——String字符最大长度的探索 111 话题20 追本溯源——追寻String字面常量的“极限” 116 话题21 旧调重弹——再论equals方法与“==”的 区别 122 话题22 顺藤摸瓜——从字面常量到String常量池 136 第4章 方法、构造器与变量 143 话题23 相差无几——main方法很“特殊”吗? 143 话题24 一词多义——方法重载的详细说明 150 话题25 踵事增华——方法重写的真正条件 166 话题26 一叶障目——方法与成员变量的隐藏 177 话题27 发轫之始——执行初始化的构造器 182 话题28 殊途同归——成员变量不同的初始化方式 193 话题29 按部就班——初始化顺序与向前引用 206 第5章 类与接口 220 话题30 相辅相成——基本数据类型与包装类 220 话题31 分门别类——数组的阐述 232 话题32 规矩方圆——定义规范的接口类型 242 话题33 彻里至外——嵌套类型 248 话题34 不胜枚举——枚举的神秘 258 话题35 按部就班——加载、链接与初始化 265 话题36 择优录取——类型及其成员的选择 283 内容简介 本书分为5章,分别为“基本概念”,“运算符与表达式”,“String类”,“方法,构造器与变量”,“类与接口”。 通过以上方面介绍那些常见、常用却少为人知的Java知识。虽然内容相对基本,但都不是容易解答的。目前更多的开发人员(不乏多年开发经验者),也仅仅停留在Java表面的层次,而本书,将更深入一层地去讨论Java的话题,令读者耳目一新,知其然,更知其所以然。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值