好好学Java:从零基础到项目实战
上QQ阅读APP看书,第一时间看更新

2.1.2 特殊数字的表达

之前提到,Java语言不但支持大众熟知的十进制数,也支持计算机特有的二进制数、八进制数和十六进制数。可是在给数值变量赋值的时候,等号右边的数字明显属于十进制,那么究竟要如何书写其他进制的数字呢?为此Java规定了几种数字前缀,以这些前缀开头的数字就表示特定进制的数值,二进制、八进制和十六进制及其对应的前缀说明如下。

(1)二进制:该进制的数值以0b或者0B开头,其后的数字只能是0和1。注意,b是binary(二进制)的首字母。

(2)八进制:该进制的数值以0开头,其后的数字只能是0~7。

(3)十六进制:该进制的数值以0x或者0X开头,其后的数字除了0~9之外,还包括字母a~f(不区分大小写)。注意,x代表hexadecimal(十六进制)。

下面是声明各种进制变量的代码例子,依次演示二进制数、八进制数、十六进制数和十进制数的赋值操作(完整代码见本章源码的src\com\arithmetic\numerical\Prefix.java)。

public class Prefix {
    public static void main(String[] args) {
        int binary=0b11;  // 二进制数,0b也可以写成0B
        System.out.println("binary="+binary);
        int octonary=011;  // 以0开头,后面非bB、非xX的就是八进制数
        System.out.println("octonary="+octonary);
        int hexadecimal=0x11;  // 十六进制数,0x也可以写成0X
        System.out.println("hexadecimal="+hexadecimal);
        int hexLetter=0xff;  // 十六进制数不区分大小写,如ff也可以写成FF
        System.out.println("hexadecimal="+hexLetter);
        int decimal=11;  // 若没有任何前缀,则默认为十进制数
        System.out.println("decimal="+decimal);
    }
}

运行上述代码,从运行窗口的日志观察结果如下:

binary=3

octonary=9

hexadecimal=17

hexadecimal=255

decimal=11

可见二进制的0b11转换成了十进制数为3,八进制的011转换成了十进数为8,十六进制的0x11转换成了十进数为17,十六进制的0xff转换成了十进数为255。

由于int类型最大只能表示21亿4千多万的整数,因此再大的整数就要使用long类型变量了。例如,截至2018年元旦,世界总人口数达到7 444 443 881,使用long变量保存世界人口的话,赋值代码本应如下:

        long worldPopulation=7444443881;  // 这样写会报错,因为整数默认是int类型

谁料IDEA居然报错,提示Integer number too large,意思是该数字超出了int类型的表示范围。原来Java里面的整数默认是整型的,只分配4字节的临时空间,然而7444443881超出了整型数的范围,致使默认的存储空间不够用了。要想扩大临时的存储空间,得在数字后面补上小写的l或者大写的L,表示该整数要求分配8字节的长整型临时空间,这样才供得起7444443881这个大神。于是修改后的长整型赋值代码如下(完整代码见本章源码的src\com\arithmetic\numerical\Suffix.java):

        // 截至2018年元旦,世界人口大约有74亿
        long worldPopulation=7444443881L;  // 长整型数要在数值末尾加上l或者L
        System.out.println("worldPopulation="+worldPopulation);

注意,上面的代码末尾的L只表示数据类型,变量值并不包括L这个字母。运行测试代码,可见日志打印结果为“worldPopulation=7444443881”。

刚提到Java的整数默认是整型的,相对应的,Java的小数默认是双精度类型的,那么试试下面的代码能否将小数赋值给float变量?

        float huilv=3.14;  // 这样写会报错,因为小数默认是double类型的

果然IDEA提示出错了“Incompatible types”,意思是类型不匹配,正确的写法要在小数末尾补上小写的f或者大写的F,表示该小数按照浮点数类型分配存储空间。改写后的浮点数赋值代码如下:

        // 3.14是中国古代数学家刘徽求得的圆周率数值,又称徽率
        float huilv=3.14F;  // 浮点数要在数值末尾加上f或者F
        System.out.println("huilv="+huilv);

其实小数后面也可以补上d或者D,表示该小数按照双精度类型分配存储空间,只是因为Java的小数默认就是double类型的,所以小数后面的D可加可不加,不影响正常的编译。

这下几种数字类型都能够正确地赋值了。但是还有一个细节问题,当数字的位数很多的时候,后面有多少个零会让初学者看得眼花缭乱。现实生活中,整数通常每隔4位就在中间补上空格或者补上逗号。譬如中国的领土面积是960万平方公里,实际书写一般为9 600 000或者9,600,000,这样可以很清楚地区分万的单位乃至亿的单位。从Java 7开始,允许在数字中间插入下画线作为分隔符,下画线本身没有保存到变量中,它的作用类似前面的空格和逗号,仅仅是方便程序员数清具体的位数而已。

下面是在数字变量赋值时添加下画线的代码例子:

    // 中国的领土面积是960万平方千米
    int chinaArea=960_0000;  // 从Java 7开始,数字中间允许添加下画线,从而可以更方便地区分位数
    System.out.println("chinaArea="+chinaArea);

虽然下画线方便了程序员数数,数字的长度却变得更长了,倘若再来一个更大的整数,例如太阳到地球的距离为1.5亿千米,展开可是150000000千米,Java赋值加了下画线则为1_5000_0000,此时后面拖了许多个零。在数学上,可以通过科学记数法表示这种较大的数,也就是把一个数书写成a×10n的形式(1≤a<10)。Java代码也有与科学记数法类似的表达方式,像1.5亿这个数字,其实等于1.5×108,在代码中可以通过E8或者e8表示108,于是采取科学记数法的Java赋值代码如下:

        // 太阳距离地球1.5亿千米
        double sunDistance=1.5E8;  // E8表示乘以108,E是exponent(指数)的首字母
        System.out.println("sunDistance="+sunDistance);

注意上述代码中的1.5是小数,所以必须使用双精度数作为赋值变量,而不能用整型或长整型数。即使E前面的数字是整数,该变量也只能是双精度类型,因为Java约定了科学记数法专用于双精度数字。