透析Java本质的36个话题01基本概念

开门见山

IEEE 754 算数标准

关于IEEE 754标准下的浮点数
(全文以64位为例,规定64位中包括1位符号位,11位阶码和52位尾数)

1.符号位
2.阶码
阶码由于偏移量的存在,其值会被加上1023(在IEEE754中特殊规定的,纯粹为了方便计算)。
    		(类似于整形 +- 进行运算,进行移码)
例如:
	如果本来是2的5次方,那么转换后将会是1028,即(10000000100)2;
	如果是2的-1次方,转换后将会是1022,即(01111111110)2。
那么阶码的取值,在0至2047之间。其中,0和2047是特别的,如果是2047,那么无论尾数是多少,这个数都是无穷大,即溢出。而当阶码是0时,将分开另讲。
3.尾数
    	。。。。 待定,找时间看一下算数标准
    	老生常谈:绝对值超出上界上溢,溢出处理报错;绝对值超出下界下溢,按机器0处理,不报错。
  1. float类型在Java中占用4字节,long类型在Java中占用8字节,为什么float类型的取值范围比long类型的取值范围还大?

    float类型的取值范围为3.4E-38至3.4E+38,而long类型的取值范围为-9.2E+318至9.2E+318。
    原因在于浮点数和整数在计算机中表示方式不同。
    	浮点数使用的是IEEE 754标准,它使用指数和尾数来表示实数,因此可以在较小的存储空间内表示非常大或非常小的数。
    	整数使用二进制补码表示法。
    	
    
  2. 在Java中,类型会在什么时间、什么条件下由JVM加载?加载后一定会初始化吗?

    在Java中,类型(类或接口)的加载 初始化 卸载是由JVM的类加载器(ClassLoader)来负责的。
    	1.遇到new、getstatic、putstatic或invokestatic指令时
    	2.JVM启动
    	3.反射
    注意:  类的初始化是指敬爱代码库阿爹执行和静态变量的赋值。类的实例化是创建类的对象
    
  3. 内部成员类是如何绑定外围类对象的?

    Java中,内部类可以访问外围类的成员(变量、方法),这种绑定是通过使用外围类对象的引用来实现的。
    

世外隐居-关键字

goto const , 可以作为关键字(也就是保留字)

  1. goto 跳转, java中取而代之的是循环标签1
  2. const 只作为保留字

true 、false 与null

Java中,这三个符号是3个字面常量(直接量) 
	true/false 是布尔类型的字面常量
	null是引用类型的字面常量
	但是同样不能作为标识符使用。

疑团满腹-标识符更深层的思考

  • 标识符定义规则

    • 1.标识符的首字符所对应的代码点必须使得Character类的 isJavaldentifierStart方法返回值true,后续字符所对应的代码点(如果存在后续字符的话)必须使得 Character 类的JavaldentifierPart 方法返回值为 true。
      2.标识符不能与Java中的关键字相同。
      3.标识符不能和Java中预定义的字面常量名称相同( true、false、null)。
      4.标识符的长度必须在系统所支持的范围内(这点是Java 虚拟机要求的)。
      
  • 标识符首字符允许使用的字符

  • 标识符首字符允许使用的字符

  • 勿用“$”

    • $被编译器所使用, 在源文件编译成字节码文件后,会成为顶层类型与嵌套类型之间的连接符。
      
  • 标识符最大长度

    • Java语言规范中,长度任意。但是在Java虚拟机规范中,标识符有长度限制。在class文件中,代表标识符的常量字符存储在CONSTANT_Utf8_info表中, 使用2Byte lengh标识长度, 2^16 -1 --> 65536. 这个长度仅限于没有 空字符 null 以外的ASCII字符

鞭长莫及-特殊字符

  • 转义序列符的使用。

    • public class Escape {
      //char cl = '\u0027';
      // char c2 - '\u005c';
      //String s ="\u0022";
      //分别是 "'' "\" """ 编译错误    
      
      // char c3 = '\400';
      // char c4 = '\28';
          //八进制转义,c4出现8显然错误, 八进制转义范围有限,合理范围是0~255
      }
      
  • 八进制转义的使用。

  • Unicode转义的使用。

    • 尽管我加上了注释, 依然无法编译通过。

      //char cl ='\u000a';
      //char c2= '\u000d';
      //c1是一个换行
      //c2 是一个回车
      

      **为什么编译无法通过? **

      因为Unicode转义字符处理的非常早。 在编译器将程序解析成各种符号之前,就会先将unicode 转义字符转换为其所表示的字符,这个过程是在编译器丢弃空白与注释之前进行的。
         
          
          解析代码之后-->
          //char cl =' //换行
          ';
      //char c2= '//空格
          ';
      
  • 3种转义字符的区别与联系。

    • 普通字符 、八进制转义unicode字符、16进制unicode字符
  • Unicode转义字符的特殊性。

  • 增补字符的使用。

    • 增补字符

      • 对于增补字符, 是使用两个字符(一个代理对)来转义处理的。而要写成两个unicode转义  \ud800\udc00
        
      • char c2='𨸖';
        //当然会报错 
        //汉语字符一般又 两个UTF-16字符组成
        //也就是增补字符,已经超过了char类型 最大值65535
        
      • //        28e16
                int codePoint = 0x28e16;
        //        转为字符数组
                char[] chars = Character.toChars(codePoint);
                String s = new String(chars);
                System.out.println(s);
        
        //      高代理字符编码值/低。。。。
                char highed = Character.highSurrogate(codePoint);
                char lowed = Character.lowSurrogate(codePoint);
                System.out.println(highed);
                System.out.println(lowed);
        
                int codePoint1 = Character.toCodePoint(chars[0], chars[1]);
                System.out.println(Integer.toHexString(codePoint1));
        
        	注意转义序列符、八进制转义、Unicode转义的使用。Unicode转义的处理时期要早于转义序列符与八进制转义。
        	Unicode 转义处理时期是在编译器将程序解析成各种符号前就进行的。如果\u后没有接4个十六进制数字,将会产生编译错误,就算在注释中也不例外。
        	增补字符使用两个代码单元(一个代理对)来表示。因此,所有增补字符都不能使用char类型的常量来表示。
        	增补字符代理对的值区间为U+D800~U+DFFF,该区间没有分配字符。利用这个特征,程序就可以来区分一个 char类型的字符到底是单个字符还是一个增补字符的代理字符。
        

移星换斗——从 byte b=1谈类型转换的神秘

记得大致是这样的,随手画了下

整形之间的转换

​ byte、short、char、int、long

首先 char是无符号类型,因此char与byte类型不存在自己关系,也就是说char与其他两种类型总是需要类型转换
	其次,当byte short int 类型或者三者 进行运算时,结果类型都为int类型,而非较高的类型。 byte + short = int 

byte b = -10; //1 
char a = (char)b; //2
System.out.println(a+1);
int c  = a; //65526 
System.out.println(c);

2.将int类型转换成char类型,直接截取低16位,补码为:1111 1111 1111 0110  //(此处分为正负数,决定是否补0 /1)
然后,执行第12行,再次将char类型转换成int类型,因为char为无符号类型,扩展的16位为0,补码为;
000000000000 0000 1111 1111 1111 0110因此,结果就输出了65526。

整形到浮点类型的转换

​ s 与 f 的运算都为 double类型。

​ f 的范围远大于 d , 所以进行转换,不需要考虑符号,直接补位。(d-->f)

注意:

·如果变量的类型是 byte、short或char类型,当对其赋予编译时期的常量,而该常量又没有超过变量的取值范围时,编译器就可以进行隐式的收缩转换。这种隐式的收缩转换是安全的,因为该收缩转换只适用于变量的赋值,而不适用于方法调用语句,即不适用于方法调用时的参数传递。

·注意char类型,这是一个无符号类型。因此,char与 short或char与 byte之间的转换都必须显式地使用类型转换。

·从 byte到char 的转换为扩展收缩转换,该转换比较特殊,即先将byte扩展转换到int,然后再收缩转换到char。

在整型数据间的扩展转换中,如果操作数是char类型(无符号类型),则进行无符号扩展,扩展位为0。如果操作数是 byte、short或int(有符号类型),则进行有符号扩展,扩展位为该变量的符号位。

整型数据之间的收缩转换,仅仅是截断并丢弃高位,不做任何其他处理。

扑朔迷离——浮点类型的种种悬疑

浮点类型只是近似的存储

​ 0.1 + 0.2 != 0.3 在计算机中。 计算机所有数据都用二进制来表示,只能准备表示2^-1 ..-2 二分这种数据。

数量级别很大的浮点运算

   float a = 300000000;
        float b = a +1;
        if(b > a){
            System.out.println("a is lighter");
        }else {
            System.out.println("b is larger");
            //会输出这一行
        }   

这是由于浮点值的存储造成的,二进制所能表示的两个相邻的浮点值间存在一定的间隙,浮点值越大,这个间隙越大。达昂浮点值达到一定程度时,如果浮点值改变很小,就不足以使浮点值发生变化

从浮点类型到整形的转换

  1. 从浮点收缩转换为Long
    • 如果浮点值为NaN,则结果为OL。如果浮点值不是士Infinity,则将浮点值向0舍入为整型值。如果该整型值在long类型的取值范围内,则转换结果就是long类型的整型值。反之,该浮点值一定很大或很小(包括土Infinity),则结果为long类型的最大(小)值。
  2. 从浮点收缩转换int类型
    同上,只是最大值为int最大值。变笑了
  3. 从浮点类型收缩转换为byte、char、short类型
    • 在转换为int类型的基础上,进一步收缩为相应的类型
	理解浮点类型数据的不精确性。十进制表示的浮点值只有很小一部分可以使用二进制准确存储,大多数存储的都是近似值。
	留意浮点类型,在使用浮点类型做比较运算时需要格外小心。另外,在数量级相差很大的浮点数据间做加减运算可能也无法得到预期的结果。
	从整型转换为浮点类型时,如果整型数据的值过大(小),就可能损失一些最低有效位,从而造成数值的不准确性。
	·理解浮点类型转换为整型的转换过程。

水落石出-浮点结构的最终解密

重点摘要:
浮点类型数据的存储结构。
正规化浮点数与非正规化浮点数。特殊值浮点数。
浮点数据符号位,指数域与有效位数域的取值范围。·浮点数据近似存储的原理。
浮点数之间的间隙。
最近舍入模式。

浮点数据的存储

浮点类型的结构与运算符合IEEE754标准。	
	浮点类型使用符号位、指数与有效位数(尾数)来表示。
符号位 指数域 有效位数域
float 1位(31位) 8位(23~30位) 23位(0~22位)
double 1位(63位) 11位(52~62位) 52位(0~51位)

浮点数三类

  1. 正规化浮点数

    指数域不全为0且不全为1,这就是正规化浮点数。 正规化浮点数的有效位数(小数部分)会在实际存储小数值的结果上加1.
    例如float类型99.5f的32位存储结构:	
    	0-10000101-10001110000000000000000
    	指数部分是10000101-01111111  得到6
    	后面这个127是float 32位指数部分运算规定的数值,便于数据的运算。
    	对于有效部分: 0.1000111 , +1 --》 1.1000111
    	99.5f = 1 x 1.1000111 x 2^6
    	
    在IEEE 754标准中,double类型的浮点数使用二进制科学计数法来表示,其指数范围是-1022到1023。为了使得浮点数能够正确地表示出来,当指数为0时,偏移量为0;当指数为正数时,偏移量为1023;当指数为负数时,偏移量为-1022。
    
  2. 非正规化浮点数

    当指数域全为0并且有效位数域不为0时,这就是非正规化浮点数。
    注意:  非正规浮点数的指数值为1-偏移量。另外--> 有效位数(小数部分)就是实际存储结果(不再加1)
    
  3. 特殊浮点数

    符号位 指数域 有效位数域
    0 0 全为0 全为0
    -0 1 全为0 全为0
    正无穷大 0 全为1 全为0
    负无穷大 1 全为1 全为0
    NaN 任意 全为1 不全为0

    近似存储

    ​ 十进制小数部分转换成计算俺记得二进制存储时,采用的是乘2取整法。直到积为1.

    浮点数值之间的间隙

    ​ 所能存储的两个临近小数之间的差值,就是浮点数值的间隙。

    龙虎争霸-基本for循环域加强型for循环的对比

    • 加强型for循环的优势。
      • 方便 明显
    • 加强型for循环的局限与不足。
      1. 只能对元素进行顺序的烦阿戈文
      2. 只能访问数组(集合)中的所有元素
      3. 在循环中没有当前的索引,无法对指定元素进行操作
    • 加强型for循环的底层实现。
      • 加强for条件要求右侧的变量必须是数组或者IIterable类型

posted @ 2023-11-26 22:38  lartimes  阅读(32)  评论(0)    收藏  举报