基本数据类型

来源:互联网 发布:网络流量监视软件 编辑:程序博客网 时间:2024/05/16 10:49

             八种基本数据类型一览表


备注:1丶(short)0表示的是默认值是short类型的0,(byte)0同理。

          2丶0L表示长整型的0,0.0f、0.0d同理,其中字母L、f、d不区分大小写只是作为数据类型的标识用于区分数据的类型。

          3丶"\u0000"是Unicode码,代表一个空格的意思。

          4丶除了boolean类型,其它数据的表示范围,不必强记(言下之意就是除此之外的都要求记忆)。

分类图:

基本知识:Java是强类型语言,强类型包含两方面的含义:
①所有的变量必须事先声明、后使用。
②指定类型的变量只能接受类型与之匹配的值。这意味着每个变量和每个表达式都有一个在编译时就确定的类型。类型限定了一个变量能被赋的值,限制了一个表达式可以产生的值,限制了在这些值上可以进行的操作,并确定了这些操作的含义。

重点一:编程的本质,就是对内存中数据的访问和修改。程序所用的数据都会保存在内存中,程序员需要一种机制来访问或修改内存中数据。这种机制就是变量,每个变量都代表了某一小块内存,而且变量是有名字的,程序对变量赋值,实际上就是从该变量所代表的内存区取值的过程。形象的理解:变量相当于一个有名称的容器,该容器用于装各种不同类型的数据。

我们先来看这样一道Java程序题:


乍一看,好像是输出66666,但经过实践,它输出的却是17777!为什么会这样?难道Java对于打印66666这样的非常数字抱有偏见吗?这明显不是一个合理的解释。事物往往有别于它的表象,请再仔细的观察一遍括号内的操作数,12345并没有问题,但是5432l不是54321!是一个12345的int类型加到了long类型的5432上。这个题目给了我们两个教训:
1、即使不区分大小写,但long类型的L一定要大写!
2、类似的,要避免用单独的l字母作为变量名,防止与数字1混淆。

细心的童鞋可能已经发现了上表中“可表示的数据范围”有着某种规律:-x~x-1。

这个“可表示的数据范围”究竟是怎么得出的呢?网上对这个问题给出的答案其实有许多错误,这个问题涉及计算机的三种码:原码、反码和补码。
首先我们明确第一点:一个字节可以储存八位二进制数,第二点:Java用补码来表示二进制数。

在计算机内,定点数有3种表示法:原码、反码和补码

原码就是二进制定点表示法,即最高位为符号位,“0”表示正,“1”表示负,其余位表示数值的大小。如(1000 0000)就表示-0。

反码表示法规定:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。如(1000 0000)的反码就是(1111 1111)(一样表示为-0)。

补码表示法规定:正数的补码与其原码相同;负数的补码是在其反码的末位加1。

那么用byte类型举例,一个字节的它最大的二进制数就是(0111 1111),首先0是符号位,而且正数的源码和补码相同,所以换算成十进制就是127。在这里又要明确一点:补码和反码都是原码经过变换得来的,我们最终都要把补码或者反码转换成原码进行计算。也就是说,问题是:一个怎么样的八位二进制数补码换算成原码时是最小的。

我们先来进行这样一个运算:

原码八位二进制数范围:(1111 1111)~(0111 1111);换算成十进制是:-127~127。

由补码和原码的关系可以得补码八位二进制数范围:(1000 0001)~(0000 0001);换算成十进制:-127~127。

这时读者肯定会吐槽我,这有什么鬼用?

先等等,你是否有一个疑惑?

我们由原码通过运算得出的补码八位二进制数范围:(1000 0001)~(0000 0001),这个范围是真的吗(逻辑上并没错)?为什么不是(1000 0000)~(0000 0000)呢?我相信你决不可能一眼看出(1000 0000)与(1000 0001)这两个补码的大小,它们谁大?

那我们来实践一下,(0000 0000)是整数(原码变补码第一位符号位是不会变的,所以可以通过补码直接看出是正数)那它表示的就是0。等等,问题来了,(1000 0000)换算成原码应该先减一然后除符号位取反,但是(1000 0000)怎么减一(1是符号位,不参与运算)?难道(1000 0000)补码代表的就是那个数?

要解决以上问题,还得从头说起:

数值有正负之分,计算机就用一个数的最高位存放符号(0为正,1为负)。这就是原码的由来。我们假设机器能处理的位数为8。即字长为1byte,那么原码能表示数值的范围为(-127~-0 +0~127)共256个。

有了数值的表示方法就可以对数进行算术运算。

但是很快就发现用带符号位的原码进行乘除运算时结果正确,而在减法运算的时候就出现了问题(假设字长为8bits):

( 1 ) 10 - ( 1 )10 =  ( 1 )10 + ( -1 )10 =  ( 0 )10
(0000 0001)原 + (1000 0001)原 = (1000 0010)原 = ( -2 ) 错误
因为在两个整数的加法运算中是没有问题的,于是就发现问题出现在带符号位的负数身上。

所以对除符号位外的其余各位逐位取反就产生了反码。反码的取值空间和原码相同且一一对应

下面是反码的减法运算:
 ( 1 )10 - ( 1 ) 10=  ( 1 ) 10 + ( -1 ) 10=  ( 0 )10
 (0000 0001) 反+ (1111 1110)反 =  (1111 1111)反 =  ( -0 )  错误

( 1 )10 - ( 2)10 =  ( 1 )10 + ( -2 )10 =  ( -1 )10
(0000 0001) 反+ (1111 1101)反 =  (1111 1110)反 =  ( -1 )  正确
问题出现在(+0)和(-0)上,在人们的计算概念中零是没有正负之分的

为了解决这个问题,人们引入了补码概念。补码表示的数据数量和原码一样但数值不完全相同。

在八位二进制(别的位数可以“正常”表示-128)补码中用(-128)代替了(-0)。

所以八位二进制数补码的表示范围为:(-128~0~127)共256个。
同时我们规定(-128)的八位二进制补码是(1000 0000)。

值得一提的是(-128)在八位二进制数里面没有原码和反码(在其它位数有多个)——如果你还问为什么那就说明你没认真看上文。

抛砖引个玉:其实(-128)只是八位二进制数里的特例,在其它位数中取代(-0)成为特例的数还有很多,但它们都有一个共同特点:它们只是个别位数下的奇葩,在其它位数里它们和别的数并无差别。

总结几点:

1丶计算机由原码衍生出反码、补码其目的都是解决原码所存在的问题,这一点和数学的发展史其实是类似的:都是为了解决老知识(规则)所不能解决的问题而创造了新知识(规则)(比如0和负数的引入,都是为了解决运算问题)。

2丶补码设计目的:通俗的说就是为了解决原码运算会出错的问题而制定一套编码,因为原码所表示的数中是有(-0)这个数的,为了阻止它的扰乱,人类才创造出了补码(其实还涉及到一个“模”的概念)。科学地说:补码能使符号位与有效值部分一起参加运算,从而简化运算规则;使减法运算转换为加法运算,进一步简化计算机中运算器的线路设计。

3丶由于在Java中采用的是补码(原因2丶),而补码表示的个数和原码是一样的,但是范围不一样。这也是为什么我们无法用计算得出(-128)这个数,因为这个是规则(不了解它不可能知道(-128)的由来),就好像数学中规定任何数的0次幂都是1。这是人类为了解决问题而制定的规则。


1 0
原创粉丝点击