java数据类型最全讲解(java核心技术-12版卷Ⅰ-)

以下内容为原书中文版原文,如有错别字,请评论留言指正

其中 绿色“补充”为我个人备注补充的内容,其他的包括 注释,C 注释,警告等都是原书内容

java数据类型最全讲解(java核心技术-12版卷Ⅰ-)(1)

Java是一种强类型语言。这就意味着必须为每一个变量声明一个类型。在Java中,一共有8种基本类型(primitive type),其中有4种整型,2种浮点类型、1种字符类型char(用于表示Unicode编码的代码单元,请参见3.3.3节char 类型)和1种用于表示真值的boolean类型。

注释:Java有一个能够表示任意精度的算术包,所谓的“大数”(big number)是Java对象,而不是一个基本Java类型。本章稍后将会详细地介绍如何使用大数。

3.3.1 整型

整型用于表示没有小数部分的数,可以是负数。Java提供了4种整型,如下。

java数据类型最全讲解(java核心技术-12版卷Ⅰ-)(2)

在通常情况下,int类型最常用。但如果想要表示整个地球的居住人口,就需要使用long类型了。byte和short类型主要用于特定的应用场合,例如,底层的文件处理或者存储空间有限时的大数组。

在Java中,整型的范围与运行Java代码的机器无关。这就解决了软件从一个平台移植到另一个平台时(或者甚至在同一个平台中不同操作系统之间移植时)让程序员头疼的主要问题。与此相反,C和C 程序会针对不同的处理器选择最高效的整型,这样一来,一个在32位处理器上运行得很好的C程序在16位系统上可能发生整数溢出。由于Java程序必须保证在所有机器上都能够得到相同的运行结果,所以各种数据类型的取值范围是固定的。

长整型数值有一个后缀L或l(如40000L)。十六进制数值有一个前缀0x或0X(如0xca21)。八进制有一个前缀0(比如010对应十进制中的8)。显然,八进制表示法容易混淆,Java程序员很少使用八进制。

加上前缀0b或0B还可以写二进制数。例如0b1001就是9。另外,可以为数字字面量加下划线,如(1_0000_0000)表示1亿。这个只是为了方便程序员,编译器实际识别时会自动去掉这些下划线。

C 注释:在C和C 中,int和long 等类型的大小与目标平台相关。在8086这样的16位处理器上,整数占2字节;不过在32位处理器上,整数则为4字节。类似的,在32位处理器上long为4字节,在64位处理器上为8字节。由于存在这些差别,这给编写跨平台程序带来了很大难度。在Java中所有数值类型的大小都与平台无关。

注意,Java没有无符号(unsigned)形式的int、long、short、或byte类型。

注释:如果使用不可能为负的整数值而且确实需要额外的一位(bit),也可以把有符号整数解释为无符号数,但要非常仔细。例如,一个byte值b可以不表示-128~127,如果你想表示0~255的范围,也可以存储在一个byte中。基于二进制算数运算的性质,只要不溢出,加法、减法和乘法都能正常计算。但对于其他运算,需要调用Byte.toUnsignedInt(b)来得到一个0~255的int值,然后处理这个整数值,再把它转为byte。Integer 和 Long 类都提供了处理无符号除法和求余数的方法。

个人补充说明

一个字节占用8个bit,整型可以表示负数,所以其中一个bit用于表示正负号,可用的存储空间就是7个,每个bit 可以有0或1两种情况(计算机底层使用2进制),所以byte的绝对值(不算正负号那一位)取值范围就是 2^7 ,又因为正负数中间有个0,这个0占了正数的一个名额,所以最终byte可用范围就是-27~2^7-1 也就是-128 ~127。

同理,int占4个字节,也就是32个bit,也需要一个bit用来做正负号,剩余可用的就是31位,所以int范围就是-231~231-1 ,也就是-2147483648~2147483647

另:我目前工作中,几乎没有用过无符号整型来计算,大多数程序的瓶颈也不在数值所占用的几个bit中,但我不能保证其他公司会不会也这样,所以,无符号整型可以先做了解,知道原理就行,后续用到的时候再深入也不迟。

3.3.2 浮点类型

浮点类型用于表示有小数部分的数值。在Java中2种浮点类型,如下。

java数据类型最全讲解(java核心技术-12版卷Ⅰ-)(3)

double表示这种类型的数值精度是Float类型的两倍(有人称之为双精度数 double-precision)。很多情况下,float类型的精度不能满足需求。实际上,只有很少的情况下适合使用float类型,例如,所使用的库需要单精度数,或者需要存储大量的单精度数。

float类型的数值有一个后缀f或者F(如3.14F)。没有后缀F的浮点数(比如3.14)会被默认为double类型。当然,也可以在double 类型数值后面添加D或者d(如3.14d)

注释:可以使用十六进制表示浮点数字面量。例如,0.125=2^3可以写为0x1.0p-3。在十六进制表示法中,使用p表示指数,而不是e。(e是十六进制中的一个值)。注意,尾数采用十六进制,指数采用十进制。指数的基数是2,而不是10。

所有的浮点计算都遵循IEEE754规范。具体来说,有3个特殊的浮点数值表示溢出和出错情况:

  • 正无穷大
  • 负无穷大
  • NaN(不是一个数)

例如,一个正整数除以0结果是正无穷大。计算0/0或者负数的平方根结果就是NaN。

注释:常量Double.POSITIVE_INFINITY、Double.NEGATIVE_INFINITY、Double.NaN(以及相应的Float类型常量)分别表示这三个特殊值,但在实际中很少使用。特别说明,不能如下检测一个特定结果是否是NaN

if(x == Double.NaN) // 这种永远是false ,也就是两个NaN也不会相等

但可以使用if(Double.isNaN(x)) 来判断是否是NaN

警告:浮点数值不适用于无法接受舍入误差的金融计算。例如,命令System.out.println(2.0-1.1)将打印出0.899999999,而不是我们期望的0.9。这种舍入误差的主要原因是浮点数值采用二进制表示,而在二进制系统中无法精确表示分数1/10。这就好像十进制无法精确表示1/3。如果需要精确的数值计算,不允许有舍入误差,则应该使用BigDecimal类,后续会介绍这个类。

补充说明:

关于浮点数的IEEE标准,感兴趣可以进一步研究。这里提到Java中浮点的底层表示法和计算方法可以只做了解,知道可能有二进制产生的误差即可。

多数情况下,对于浮点数字,使用double即可,float使用较少。另外,有些情况下,可以通过其他方式避免浮点的舍入错误。比如,对于金钱,多数情况下,不能接受小数点误差。但根据实际情况,金钱的计数到分就可以,这种情况下,可以在底层用“分”作为单位,例如,1.3元,就保存130,而到了显示层,再进行格式化显示1.3元。

3.3.3 char类型

char类型原本用于表示单个字符。不过,现在情况已经有所变化。如今,有些Unicode字符可以用一个char值描述,另外一些Unicode字符则需要两个char值。有关的详细信息请阅读下一节。

char类型的字面量值要用单引号括起来。例如:'A'是编码值为65的字符常量。它与”A”不同,”A”是只包含一个字符的字符串。char类型的值可以表示为十六进制值,其范围从 \u0000 ~ \uFFFF。例如 , \u2122表示商标符号(TM),\u03C0表示希腊字母π。

除了转义序列 \u 之外,还有一些用于表示特殊字符的转义序列,请见表3-3.可以在加引号的字符字面量或字符串中使用这些转义序列。例如 ,'\u2122' 或”Hello\n”。转义序列 \u 还可以在加引号字符常量或字符串之外使用(而其他所有转义序列不可以)。例如:

public static void main(String\u005B\u005D args) 这种就是合法的,因为上面两个转义分别代表[ 和 ]

java数据类型最全讲解(java核心技术-12版卷Ⅰ-)(4)

警告:Unicode转义序列会在解析代码之前处理。例如,”\u0022 \u0022”并不是一个由引号(U 0222)包围加号构成的字符串。实际上,\u0022会在解析之前转换为”,这会得到 “” ”” ,也就是一个空字符串 ””。

更隐秘地,一定要当心注释中的 \u .以下注释

// \u000A is a newline

会产生一个语法错误,因为读程序时, \u000A会替换成一个换行符。类似地,下面这个注释

// look inside c:\users

也会产生一个语法错误,因为\u 后面并没有跟着4位十六进制数。

补充说明:

使用 \u000a 等格式来写字符或者字符串比较少见,更多是用在面试题或者某些地方写注释的时候因为内容中涉及了这些东西,导致的错误。平时写代码,不要刻意去写这种“炫技”的东西,老实地写,不要给自己挖坑,到时候加班挨骂,还是你自己。

不过,就像上面提到的 // look inside c:\users 这种错误就是容易不小心触发,好在,在ide环境下,这样的错误立刻就会报红,我们看到错误,改掉就好了,也不必太过担心,只需要对 \ 这个转义符稍加留心即可。

3.3.4 Unicode 和 char类型

要想弄清char类型,就必须了解Unicode 编码机制,它打破了传统字符编码机制的限制。在Unicode出现之前,已经有许多种不同的标准:没过的ASCII、西欧语言的 ISO 8859-1、俄罗斯的KOI-8、中国的GB18030和BIG-5等。这样就产生了下面两个问题:一个是对于一个特定的代码值,在不同的编码机制中可能对应不同的字母;二是采用大字符集的语言其编码长度有可能不同。例如,有些常用的字符采用单字节编码,而另外一些字符则需要两个或多个字节编码。

设计Unicode编码的目的就是要解决这些问题。在20实际80年代开始启动统一工作时,人们认为两字节的代码宽度足以对世界上各种语言的所有字符进行编码,并有足够的空间留给未来扩展,当时所有人都这么想。在1991年发布了Unicode1.0,当时仅占用65536个代码值中不到一半的部分。设计Java时决定采用16位的Unicode字符集,这比使用8位字符集的其他程序设计语言有了很大的改进。

遗憾的是,经过一段时间后,不可避免的事情发生了。Unicode字符超过了65536个,其主要原因是增加了汉语、日语和韩语中的大量表意文字。现在,16位的char类型已经不足以描述所有Unicode字符了。

下面利用一些专用术语来解释Java语言是如何解决这个问题的。码点(code point)是指与一个编码表中的某个字符对应的代码值。在Unicode标准中,码点采用十六进制书写,并加上前缀U ,例如U 0041就是拉丁字母A 的码点。Unicode的码点可以分成17个代码平面(code plane)。第一个代码平面称为基本多语言平面(basic multilingual plane),包括码点从U 0000到U FFFF的“经典”Unicode代码;其余16个平面的码点从U 10000到U 10FFFF,包括各种辅助字符(supplementary character)。

UTF-16编码采用不同长度的代码表示所有Unicode码点。在基本多语言平面中,每个字符用16位表示,通常称为代码单元(code unit);而辅助字符编码为一对连续的代码单元。采用这种编码对表示的每个值都属于基本多语言平面中未用的2048个值范围,通常称为替代区域(surrogate area)(U D800~U DBFF用于第一个代码单元,U DC00~U DFFF用于第二个代码单元)。这样设计十分巧妙,因为我们可以很快知道一个代码单元是一个字符 的编码,还是一个辅助字符的第一或第二部分。例如 是八元数集(https://math.ucr.edu/home/baez/octonions/)的数学符号,码点是U 1D546,编码为两个代码单元U D835和U DD46(关于编码算法的具体描述见 https://tools.ietf.org/html/rfc2781)

在Java中,char类型描述了采用UTF-16编码的一个代码单元。

强烈建议不要在程序中使用char类型,除非确实需要处理UTF-16代码单元。最好将字符串作为抽象数据类型来处理(有关这方面的内容将在3.6节讨论)。

补充:

根据编码输出相应的字符

public static void main(String[] args) { int code = Integer.parseInt("1D546",16); // U 1D546 就是字符编码,其对应的字符为 char[] cs = Character.toChars(code); System.out.println(new String(cs)); }

3.3.5 boolean 类型

boolean(布尔)类型有2个值:false和true,用来判断逻辑条件。整型值和布尔直接不能相互转换

C 注释:

在C 中,数值甚至指针可以代替布尔值。值0相当于布尔值的false,非0相当于true。在Java中,不是这样。因此Java程序员不会遇到以下麻烦:

if(x=0) // oops ... meant x==0

在C 中这个测试可以编译运行,其结果总是false。而在Java中,这个测试将不能通过编译,其原因是整数表达式x=0 不能转换为布尔值。

补充说明:

x=0表示赋值,就是将x设置为0,并且其返回值是x,所以,可以这么写 z=y=x=0,表示把这三个变量都设置为0; 而x==0则是判断x和0是否相等,可以这么写 boolean b = x==0 ,其结果为 false 或true。

本节内容先做了解,知道Java中有哪些基本的数据类型,对于相关的规定和定义,如果能理解最好,如果不能理解,不要把精力放在这儿,先向后继续学习,尤其是char 相关的UTF-16的内容,但是需要知道一个概念,在Java中因为UTF-16,可能导致看上去是一个字符的字符串,其长度为2,这是UTF-16编码造成的(就像有时候一个人买两个票一样,得占两个位置,没办法,一个位置坐不下)。

后面这些类型,我们都会反复使用,不用担心不了解,尤其是int boolean ,

个人使用频率大概是 int boolean > long double > byte float > char > short

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页