赞
踩
数据类型实质上是用来定义编程语言中相同类型的数据的存储形式,也就是决定了如何将代表这些值的位存储到计算机的内存中。
所以,数据在内存中的存储,是根据数据类型来划定存储形式和存储位置的。
那么
Java的数据类型有哪些?
- 4种整数类型:byte、short、int、long
- 2种浮点数类型:float、double
- 1种字符类型:char
- 1种布尔类型:boolean
Java中数据类型主要分为两大类:基本数据类型和引用数据类型。
8种基本数据类型:boolean、byte、char、short、int、long、float、double,及对应包装类型如下:
对应包装类型的常量缓存以及自动装箱拆箱的坑参见上篇博客:
在Java中,整数类型(byte/short/int/long)中,对于未声明数据类型的整形,其默认类型为int型。在浮点类型(float/double)中,对于未声明数据类型的浮点型,默认为double型。
java中不存在byte/short型常量的表示法。但可以把一定范围内的int型常量赋值给byte/short型变量。jvm自动进行隐式类型转换,方法推测是进行低位截取。
如上图所示,可以将-128~127范围内的int 值赋给byte,当128超过范围赋给byte时就需要强制转化(byte)128
其值为-128,即二进制0b1000_0000代表byte的-128
当将一个数值范围小的类型赋给一个数值范围大的数值型变量,jvm在编译过程中将此数值的类型进行了自动提升。比如long a = 1;
自动将int型1提升为long型。
但这个过程并非简单的高位补0,而是根据值的符号情况进行零扩展
与符号扩展
,以保证类型提升后数值不变。
例如:
long a = -1;
System.out.println(a);//-1
short st = -200;
int it = st;
System.out.println(it);//-200
符号扩展(Sign Extension)用于在数值类型转换时扩展二进制位的长度,以保证转换后的数值和原数值的符号(正或负)和大小相同,一般用于较窄的类型(如byte)向较宽的类型(如int)转换。扩展二进制位长度指的是,在原数值的二进制位左边补齐若干个符号位(0表示正,1表示负)。
举例来说,如果用6个bit表示十进制数10,二进制码为"00 1010",如果将它进行符号扩展为16bits长度,结果是"0000 0000 0000 1010",即在左边补上10个0(因为10是正数,符号为0),符号扩展前后数值的大小和符号都保持不变;如果用10bits表示十进制数-15,使用“2的补码”编码后,二进制码为"11 1111 0001",如果将它进行符号扩展为16bits,结果是"1111 1111 1111 0001",即在左边补上6个1(因为-15是负数,符号为1),符号扩展前后数值的大小和符号都保持不变。
这个规则是《Java解惑》总结的:如果最初的数值类型是有符号的,那么就执行符号扩展;如果是char类型,那么不管它要被转换成什么类型,都执行零扩展。还有另外一条规则也需要记住,如果目标类型的长度小于源类型的长度,则直接截取目标类型的长度。例如将int型转换成byte型,直接截取int型的右边8位。
所以java在进行类型扩展时候会根据原始数据类型, 来执行符号扩展还是零扩展. 数值类型转数值类型的符号扩展不会改变值的符号和大小.
double 表示这种类型的数值精度是 float 类型的两倍(有人称之为双精度数值)。绝大部
分应用程序都采用 double 类型。在很多情况下,float 类型的精度很难满足需求。实际上,只有很少的情况适合使用 float 类型,例如,需要单精度数据的库, 或者需要存储大量数据。
float 类型的数值有一个后缀 F 或 f (例如,3.14F。) 没有后缀 F 的浮点数值(如 3.14 ) 默
认为 double 类型。当然,也可以在浮点数值后面添加后缀 D 或 d (例如,3.14D)。
表示方法
参考:Java字符编码原理总结
boolean (布尔)类型有两个值:false 和 true, 用来判定逻辑条件。 整型值和布尔值之间
不能进行相互转换。
Java语言对布尔类型的存储并没有做规定,因为理论上存储布尔类型只需要1 bit,但是通常JVM内部会把boolean表示为4字节整数。
具体boolean占用多少字节参考:
隐式转换也叫作自动类型转换
, 由系统自动完成。
byte ->short(char)->int->long->float->double
+=
或者 ++
运算符也可以执行隐式类型转换。如:显示类型转换也叫作强制类型转换
, 是从存储范围大的类型到存储范围小的类型。
当我们需要将数值范围较大的数值类型赋给数值范围较小的数值类型变量时,由于此时可能会丢失精度(前面讲的隐式赋值除外),因此,需要人为进行转换。我们称之为强制类型转换。
double→float→long→int→short(char)→byte
byte a =3;编译正确之前解释过了。接下来将一个值为3的int型变量b赋值给byte型变量c,发生编译错误。这两种写法之间有什么区别呢?
区别在于前者3是直接量,编译期间可以直接进行判定,后者b为一变量,需要到运行期间才能确定,也就是说,编译期间为以防万一,当然不可能编译通过了。此时,需要进行强制类型转换。
强制类型转换所带来的结果是可能会丢失精度,如果此数值尚在范围较小的类型数值范围内,对于整型变量精度不变,但如果超出范围较小的类型数值范围内,很可能出现一些意外情况。
上面的例子中输出值是 -23.
为什么结果是-23?需要从最根本的二进制存储考虑。
233的二进制表示为:24位0 + 11101001,byte型只有8位,于是从高位开始舍弃,截断后剩下:11101001,由于二进制最高位1表示负数,0表示正数,其相应的负数为-23。
switch(exper)
在Java5以前,exper只能是byte
,short
,char
,int
类型
byte、short、char
类型可以在不损失精度的情况下向上转型成int
类型。
在Java5开始,java中引入了枚举类型(enum
类型)和byte,short,char,int的包装类
四个包装类的支持是因为java编译器在底层进行了拆箱操作
;
枚举类型的支持是因为枚举类有一个ordinal
方法,该方法实际上是返回一个int
类型的数值。
在Java7开始,exper还可以是String
类型
String类中因为有一个hashCode
方法,结果也是返回int
类型
多重转型
连续三次类型转换的表达式如下:
(int)(char)(byte)-1
-1
是int
型的字面量,根据“2的补码”编码规则,编码结果为0xffffffff
,即32位全部置1.转换成byte
类型时,直接截取最后8位,所以byte结果为0xff
,对应的十进制值是-1
.
由于byte
是有符号类型
,所以在转换成char
型(16位)时需要进行符号扩展,即在0xff
左边连续补上8个1(1是0xff的符号位),结果是0xffff
。由于char
是无符号类型
,所以0xffff
表示的十进制数是65535
。
由于char
是无符号类型,转换成int
型时进行零扩展,即在0xffff
左边连续补上16个0,结果是0x0000ffff
,对应的十进制数是65535
。
几个转型的例子
在进行类型转换时,一定要了解表达式的含义,不能光靠感觉。最好的方法是将你的意图明确表达出来。
在将一个char
型数值c
转型为一个宽度更宽的类型时,并且不希望有符号扩展,可以如下编码:
int i = c & 0xffff;
上文曾提到过,0xffff
是int
型字面量,所以在进行&
操作之前,编译器会自动将c
转型成int
型,即在c
的二进制编码前添加16个0,然后再和0xffff
进行&
操作,所表达的意图是强制将前16置0,后16位保持不变。虽然这个操作不是必须的,但是明确表达了不进行符号扩展的意图。
如果需要符号扩展,则可以如下编码:
int i = (short)c; //Cast causes sign extension
首先将c
转换成short
类型,它和char是 等宽度的,并且是有符号类型,再将short类型转换成int类型时,会自动进行符号扩展,即如果short为负数,则在左边补上16个1,否则补上16个0.
如果在将一个byte数值b转型为一个char时,并且不希望有符号扩展,那么必须使用一个位掩码来限制它:
char c = (char)(b & 0xff);
(b & 0xff)
的结果是32位的int类型,前24被强制置0,后8位保持不变,然后转换成char型时,直接截取后16位。这样不管b是正数还是负数,转换成char时,都相当于是在左边补上8个0,即进行零扩展而不是符号扩展。
如果需要符号扩展,则编码如下:
char c = (char)b; //Sign extension is performed
此时为了明确表达需要符号扩展的意图,注释是必须的。
测试
Integer c1 = 0x80000000;
System.out.println(c1);//-2147483648
System.out.println((long)c1);//-2147483648
System.out.println((c1&0x00000000ffffffffL));//2147483648
显然,强制向上转型是有符号扩展,结果不变,&0x00000000ffffffffL
操作后,高32位补0,最后得到长整型2147483648
的值
Integer
源码也有将int转成无符号long型方法toUnsignedLong
public static long toUnsignedLong(int x) {
return ((long) x) & 0xffffffffL;
}
.
.
.
.
.
.
参考:
java中的基本数据类型的转换
Java 基础数据类型
java核心技术 卷I
这一次,彻底解决Java的值传递和引用传递
Java中boolean类型占用多少个字节
Java字符编码原理总结
java Integer数值==比较(自动装箱拆箱中的坑)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。