java基础-数据类型(数据表示方法、符号扩展、类型转换)


所谓数据类型,是编程语言中对内存的一种抽象表达方式,我们知道程序是由代码文件和静态资源组成,在程序被运行前,这些代码存在在硬盘里,程序开始运行,这些代码会被转成计算机能识别的内容放到内存中被执行。

数据类型实质上是用来定义编程语言中相同类型的数据的存储形式,也就是决定了如何将代表这些值的位存储到计算机的内存中。

所以,数据在内存中的存储,是根据数据类型来划定存储形式和存储位置的。
那么
Java的数据类型有哪些?

  1. 基本类型:编程语言中内置的最小粒度的数据类型。 它包括四大类八种类型:
  • 4种整数类型:byte、short、int、long
  • 2种浮点数类型:float、double
  • 1种字符类型:char
  • 1种布尔类型:boolean
  1. 引用类型:引用也叫句柄,引用类型,是编程语言中定义的在句柄中存放着实际内容所在地址的地址值的一种数据形式。它主要包括:类、接口、数组

Java中数据类型主要分为两大类:基本数据类型和引用数据类型。

基本数据类型

8种基本数据类型:boolean、byte、char、short、int、long、float、double,及对应包装类型如下:
在这里插入图片描述
对应包装类型的常量缓存以及自动装箱拆箱的坑参见上篇博客:

java Integer数值==比较(自动装箱拆箱中的坑)

在Java中,整数类型(byte/short/int/long)中,对于未声明数据类型的整形,其默认类型为int型。在浮点类型(float/double)中,对于未声明数据类型的浮点型,默认为double型。

整型

整型表示方法

  • 十进制:默认为int 型整型,末尾加上L/l表示长整型
  • 16进制: 前缀 0x/0X
  • 8进制:前缀0
  • 二进制:前缀 0b/0B
    在这里插入图片描述

byte/short表示

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

  1. 什么是符号扩展

符号扩展(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),符号扩展前后数值的大小和符号都保持不变。

  1. java中数值类型转换的规则

这个规则是《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)。

字符型

表示方法

  1. 单引号加上字符:‘A’、‘中’
  2. 整型:0~65536
  3. 转义:’\u4E2D’,范围: \u0000 ~ \uffff
    注:
    在这里插入图片描述
    字符集及编码相关知识见:

参考:Java字符编码原理总结

布尔型

boolean (布尔)类型有两个值:false 和 true, 用来判定逻辑条件。 整型值和布尔值之间
不能进行相互转换。
Java语言对布尔类型的存储并没有做规定,因为理论上存储布尔类型只需要1 bit,但是通常JVM内部会把boolean表示为4字节整数。
具体boolean占用多少字节参考:

Java中boolean类型占用多少个字节?

类型转换

在这里插入图片描述

隐式类型转换

隐式转换也叫作自动类型转换, 由系统自动完成。

  • 从存储范围小的类型到存储范围大的类型。byte ->short(char)->int->long->float->double
  • 前面讲到的利用int 值给范围内的short/char/byte赋值也可看做隐式类型转换
  • 进行算数运算时,如果包含(byte、short、char)会自动转成int,如果包含long,会上升到长整型long,如果包含浮点型则会自动将结果转型到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只能是byteshortcharint类型

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(32位) -> byte(8位)

-1int型的字面量,根据“2的补码”编码规则,编码结果为0xffffffff,即32位全部置1.转换成byte类型时,直接截取最后8位,所以byte结果为0xff,对应的十进制值是-1.

  1. byte(8位) -> char(16位)

由于byte有符号类型,所以在转换成char型(16位)时需要进行符号扩展,即在0xff左边连续补上8个1(1是0xff的符号位),结果是0xffff。由于char无符号类型,所以0xffff表示的十进制数是65535

  1. char(16位) -> int(32位)

由于char是无符号类型,转换成int型时进行零扩展,即在0xffff左边连续补上16个0,结果是0x0000ffff,对应的十进制数是65535


几个转型的例子

在进行类型转换时,一定要了解表达式的含义,不能光靠感觉。最好的方法是将你的意图明确表达出来。

在将一个char型数值c转型为一个宽度更宽的类型时,并且不希望有符号扩展,可以如下编码:

int i = c & 0xffff;

上文曾提到过,0xffffint型字面量,所以在进行&操作之前,编译器会自动将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数值==比较(自动装箱拆箱中的坑)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值