zoukankan      html  css  js  c++  java
  • 《Java深入解析》阅读笔记一(基本概念)

    1. 关键字
      1. goto和const
        1. c/c++中使用goto语句实现程序的跳转,但是由于跳转没有限制,可以随意进行,从而打破正常的程序流程,所以Java中取消了goto的使用,使用了循环标签。但是Java中依旧将goto定义为一个关键字,限制程序员将goto作为标识符使用。由于他是一个从不使用的关键字,所以也称他为“保留字”。如果使用goto或者把它作为一个变量的名称,都会产生编译错误。
        2. 在c/c++中,const是一个关键字,用来声明一个变量的值是不可变的(即通常所说的常量),与goto类似,Java语言也把const定义为关键字,但是却没有任何的语法应用,也是保留字。使用const来作为标识符也是不允许的。
      2. true,false和null(是字面常量,并非关键字,也禁止作为标识符使用)
        1. 在Java中,这3个符号是3个字面常量(也称直接量)。其中true和false是布尔类型的字面常量,null是引用类型的字面常量。这些就好比是“abc”是String类型的字面常量,二数值5就是int类型的字面常量一样。
        2. 尽管true,false,null不是关键字,但是也不能将其作为标识符使用,否则也会产生编译错误。
      3. Java关键字列表
        1. 在Java中关键字如下所示,其中goto和const为保留字,到目前为止尚未使用
        2. 关键字有如下:
          1. abstract、assert、boolean、break、byte、case、catch、char、class、const、continue、default、do、double、else、enum、extends、final、finally、float、for、goto、if、implements、import、instanceof、int、interface、long、native、new、package、private、protected、public、return、short、static、strictfp、super、switch、synchronized、this、throws、transient、try、void、volatile、while
    2. 标识符
      1. 标识符的定义规则
        1. java标识符的定义规则如下(平时使用一般不会遇到问题)
          1. 标识符由字母、数字、货币符号(¥,$等)、连接符号(_等)组成。(这里的字母为unicode字符集,而不再局限于传统的26个英文字母)
          2. 标识符的首字符可以使字母、货币符号与连接符号,但不能是数字
          3. 标识符不能与java中的关键字相同
          4. 标识符不能喝java中预定义的字面常量名称相同(true、false、null)
        2. 但是Unicode字符集的取值范围为U+0000~U+10FFFF,但是范围内不是每一个Unicode值都与一个字符对应,这意味着,并非整个Unicode字符集在java中都可以作为标识符使用。其次,不能做Java标识符首字符的字符集也不止0~9这10个字符集。可以使用character类中的两个静态方法来判断标识符的合法性。其中isJavaIdentifierStart用来判断代码点对应的字符是否可以作为Java标识符的一部分
          1. public static boolean isJavaIdentifierStart(int codePoint)
          2. public static boolean isJavaIdentifierPart(int codePoint)
        3. 重新定义标识符的定义规则
          1. 标识符的首字符所对应的代码点必须使得character类中的isJavaIdentifierStart方法返回为true,后续字符所对应的代码点必须使得character类的isJavaIdentifierPart方法的返回值为true
          2. 标识符不能与Java中的关键字相同
          3. 标识符不能喝Java中预定义的字面常量名称相同(true、false、null)
          4. 标识符的长度必须在系统所支持的范围内(这是Java虚拟机要求的)
      2. “$”标识符
        1. 尽管$可以作为标识符使用,但是我们应该尽量避免对其使用。因为$通常在编译器生成的标识符名称中使用,如果我们也使用这个符号,可能会有一些意想不到的错误发生
        2. 因为“$”在被编译器所使用,在源文件(.java文件)编译成字节码(.class文件)后,会成为顶层类型与嵌套类型之间的连接符。例如,如果存在一个顶层类A,在其内声明一个成员类B,南无编译之后就会产生两个class文件,分别为A.class与A$B.class。也就是会如果你定义一个顶层类为A.class,再再里面声明一个成员类A$B.class,那么就会生成三个文件,分别为A$B.class(顶层类),A.class与A$B.class(A类的成员类,也就是类A$B)。由于会存在两个A$B.class,所以编译会出错。
      3. 标识符的最大长度
        1. 在Java语言规范中,标识符的长度是任意的。但是,在Java的虚拟机规范中,标识符的长度是有限制的。在class文件中,代表标识符的常量字符串存储在CONSTANT_Utf8_info表中,而该表使用两个字节(length项),来表示字符串的长度,length是无符号类型,因此最大长度为2的16次方减1,即65535.这就是标识符的最大长度。但是如果标识符含有不在范围(‘u0001’~‘u007f’)的字符,会鉴赏最大长度。
    3. 特殊字符
      1. 转义字符
        1. 转义字符介绍
          1. //char c1 = 'u0027';
          2. //char c2 = 'u005c';
          3. //String s = "u0022";
          4. //char c3 = '400';
          5. //char c4 = '28';
        2. 上面那些代码,取消其中任意一行的注释,都会产生编译错误。对于1-3行,三个Unicode转义表示的字符分别为" ' "(单引号),“ ”(反斜杠)与“ " ”(双引号)。也就是等价于下面三个式子,当然他都是不正确的,经过转义过后,单引号和双引号都没有合理的匹配,而“ ”转义字符的起始字符,其后需要与其他字符结合进行转义。
          1. //char c1 =  ' ' ';
          2. //cahr c2 = ' ';
          3. //String s = " " ";
        3. 对于4、5行,使用的是八进制,八进制的允许范围为0~255,所以400超出了这个范围,而且八进制只允许出现0~7折八个数字,所以28也就不正确了。
      2. Unicode转义处理时期是在编译期将程序解析成各种符号就进行的。如果u后没有接4个十六进制数字,就会产生编译错误,就算有字符也不例外。
      3. 增补字符使用两个代码单元来表示。因此,所有增补字符都不能使用char类型的常量来表示。
      4. 增补字符代理对得知区间为U+D800~U+DFFF,该区间没有分配字符。利用这个特征,程序就可以区分一个char类型的字符到底是单个字符还是一个增补字符的代理字符。
    4. 类型转化
      1. 无形的转化
        1. 在下面这个例子里面,将整形常数变量1分别赋值给byte、char、short类型的变量,都不会发生编译错误。然而,如果把int类型的变量i对这三种变量赋值,就发产生编译错误。这种情况可以看成一种特例。对于编译时的整形字面常量(int类型),如果将其赋值给比int类型低的变量类型(byte、short或char类型),而且整型字面常量的只有没有超过该变量类型的取值范围,南无编译器就可以做隐式的类型转化。这种赋值是安全的,编译器会对字面常量的值进行检测,如果超过变量类型所能表示的范围,就会产生编译错误。而且,这种特例也有严格的限制,其,只适用于对变量进行赋值,而并不适用方法调用语句中。
          1. byte b = 1;
          2. char c = 1;
          3. short s = 1;
          4. int i = 1;
          5. //byte b2 = i;
          6. //char c2 = i;
          7. //short s2 = i;
      2. 整型之间的转化
        1. 整型包括byte,short,char,int,long5种数据类型。
          1. char类型是无符号类型(0~65535),因此char与byte(-128~127),char与short(-32768~32767)类型不存在子集关系,也就是说char与这两种类型之间的转化总是需要类型转换。
          2. 当byte,char或者short类型参与运算时,结果为int类型,而并非与较高的类型相同
          3. 复合运算符“+=”在复制时可以自动将运算结果转化为左侧的操作数类型
          4. 从byte类型到char类型的转化比较特殊,称为拓展收缩转换。因为byte类型到char类型的转化需要经过两个步骤
            1. 将byte通过扩展转化,转换为int类型
            2. 再将int类型通过收缩转换,转换为char类型
        2. 整型数据间的扩展转化,如果操作数是有符号的,扩展时就进行有符号的拓展,拓展为位为符号位。如果操作数是无符号的,额拓展是进行无符号拓展,拓展位为0,整型数据间的收缩转换,只是进行简单的截断,保留目标类型的有效位(即丢弃所有高位)
      3. 整数道浮点类型的转换
        1. 浮点类型比所有的整型的储存范围都更大,因此,在基本的数据类型中,浮点类型是比整型更高的类型,浮点类型与整型的运算,先会将整型转换成浮点类型,最后表达式的结果类型也会与浮点类型相同
        2. 所有从整数到浮点类型的转化都属于扩展转换。不过,这种转换与整数之间的扩展转化不同,整数类型之间的扩展转化是精确地,它的值不会有任何的改变,但是从整型到浮点类型的就不一样,会有精度损失。
    5. 浮点类型的各种问题
      1. 浮点类型只是近似的储存
        1. 因为计算机使用二进制存储数据,很多的小数不能够准确的用二进制来表示,就像使用十进制小数不能准确的表示1/3这样的分数一样。例如下面这个情况。看起来没有问题,但是由于浮点类型的不精准储存,f的值不会准确的加到11,所以程序永远不会结束,会陷入死循环。
          1. for(float f =10.1f;f!=11;f+=0.1f) {
            System.out.println("1");
            }

      2. 数量级差很大的浮点运算
        1. 二进制所能表示的两个相邻的浮点值之间存在一定间隙,浮点值越大,这个间隙也会越大,当浮点值大到一定程度是,如果对浮点值的改变很小,就不足以是浮点值发生改变。就好比大海蒸发了一滴水,对大海几乎没有影响。
      3. 整型到浮点类型的转换
        1. 不论是很大的正数还是很小的负数,当int类型转换为float类型,或者long类型转换为float或者double类型后,都损失了一定精度。但是从int类型到double类型的转换后,只没有改变。因为float类型可以保留7~8个有效数字,而double类型只可以保留15~16个有效数字,因而当int类型或者long类型数值的有效数字多余float或者double类型的最大有效数字的时候,该值得一些最低有效位就会丢失,从而造成精度丢失。这是就会采用IEEE754最近的舍如模式,提取与该数值最接近的浮点数值。总之就是,尽管整型相符点类型的转换属于扩展转换,但数值很大或很小时,就会产生一定的精度丢失
        2. 虽然可能产生精度丢失,从整型到浮点类型的转换可以隐式进行,无须显式的使用类型转换。
      4. 从浮点类型到整型的转换(无法理解,书本第28页,以后再来补充)
        1. 从浮点类型收缩为long类型
        2. 从浮点类型收缩转换为int类型
        3. 从浮点类型收缩转换为byte、char或short类型
      5. 要点:
        1. 浮点类型数据不精确。十进制表示的浮点数只有很小的一部分可以用二进制精确存储,大多数储存的都是近视值
        2. 在使用浮点类型作比较运算的时候格外小心。在数量级相差比较大的浮点数据做加减运算可能也无法达到预期的结果
        3. 从整数转换为浮点类型的时,如果整形数据值过于大(小),就可能损失一些最低有效的位,从而造成熟知的不准确性。
    6. 浮点结构
      1. 浮点结构的储存
        1. 在Java中,浮点类型使用符号位,指数与有效数字来表示。其中,符号位用来表示浮点值的正负,指数为用来存储数值,有效位书用来储存小数值。。在Java中float与Java的结构如下所示。
          1. 类型 符号位 指数域 有效位数域
            float

            1位(第31位)

            8位(第0~22位) 23位(第0~22位)
            double 1位(第63位) 11位(第52~62位) 52位(第0~51位)
          2. 根据指数域有效位数的不同,可以将浮点数分为3类。
            1. 正规化浮点数
              1. 当指数域不全为0,并且不全为1,该浮点数就是正规化浮点数。正规化浮点数的有效位数(小数部分)会在实际储存小数位数的结果上加一。
            2. 非正规化浮点数
              1. 当指数域全为0并且有效位数域不全为0是,该浮点数就是非正规化浮点数,需要注意的是,非正规浮点数的指数值为1-偏移量。也可以认为非正规化浮点数的偏移量比正规化浮点数的偏移量大1,只不过非正规化浮点数的指数域只有一个取值(全为0)。另外,非正规haul浮点数的有效位书(小数部分)就是实际存储的结果(不再加1)。
              2. 非正规化浮点数的有效位数值不能是0,因为非正规浮点数的指数域都是0,当有效位数域也都是0是,这个值是一个浮点类型的特殊值,也就是0.
            3. 特殊浮点数
              1. 浮点数 符号位 指数域 有效位数域
                0 0 全为0 全为0
                -0 1 全为0 全为0
                正无穷大 0 全为1 全为0
                负无穷大 1 全为1 全为0
                NaN 任意 全为1 不全为0
      2. 近似储存
        1. 十进制的小数部分转换成就算机的二进制存储是,采用的是乘2取整法,直到积为1位置。但是有的小数数值的乘积结果永远不会等于1,这就意味着,该小数值不能用二进制精准的表示,就算是double有52位有效数字,依旧不能准确存储,只是精度比23位的float类型更接近实际值而已。这就是浮点类型不能够准确存储的原因。
      3. 浮点数值之间的间隙
        1. float浮点类型从16777216开始丢失精度。因为它与下一个浮点值相差位2,对齐加一已经不足以是它“前进”到下一个浮点值
        2. 但是double存储是没有问题的,因为double有52位有效数字,足够容纳24位有效位数。
      4. 最近舍入模式
        1. 如果有一个浮点值A的有效位数超过了浮点类型(float或double)所能表示的范围,并且值A位于浮点类型所能表示的两个临近值B与C之间
          1. 如果A与B的间隙大于A与C的间隙,则选择C作为A的近似代替值。
          2. 如果A与B的间隙小于A与C的间隙,使用B来作为A的近似代替值。
          3. 当A与B的间隙等于A与C的间隙是,在B、C两者之间选择有效位数最低位为0的那个值来作为A的近似代替值。
    7. 基本for循环与加强型for循环对比
      1. 语法,由下面可以看出,无论是对数组操作,还是对集合操作,加强型for循环都比基本for循环方便一些。
        1. //基本for循环
        2. for(int i = 0;i < array.length;i++){
        3.      System.out.println(array[1]);
        4. }
        5. Iterator<String> iterator = list.iterator();
        6. //相当于while(iterator.hasNext())
        7. for(;iterator.hasNext();){
        8.       System.out.println(iterator.next());
        9. }
        10. //加强型for循环
        11. for(int  i: array){
        12.      System.out.println(i);
        13. }
        14. for(String s:list){
        15.      System.out.println(s);
        16. }
      2. 加强for循环的局限
        1. 只能对集合进行顺序访问
        2. 只能访问数组(集合)中的所有元素(不能只访问部分)
        3. 在循环中没有当前的索引,无法对制定元素进行操作
      3. 加强型for循环的处理
        1. 从底层来说,加强型for循环就是基本的for循环,只不过某些工作有编译器来转换处理了,省去了人为操作的麻烦
        2. 加强型for循环的条件要求右侧的变量必须是数组类型或者Iterable类型
  • 相关阅读:
    在类的外面调用类的private函数
    Django多表操作
    Django聚合与分组查询中value与annotate的顺序问题
    Django路由控制
    cookie与session的区别与关系
    面试题之改变对象的类
    python实现双向链表
    python实现单向循环链表
    python中的顺序表
    顺序表
  • 原文地址:https://www.cnblogs.com/SilentYears/p/10452461.html
Copyright © 2011-2022 走看看