Java自动类型提升与强制类型转换机制【详解】

在深入学习Java的底层机制的过程中,数据类型的相互转换的结果往往并符合预期。在网上查阅资料和博客时,整型部分的转换还有参考价值,但一旦涉及到浮点类型,许多博文往往一笔带过,或者语焉不详。所以笔者决心写一篇详解,说明数据类型转换时内存中究竟发生了什么,又为何会出现类型转换后与预期不符的情况。

由于文章内容大部分都是笔者自己的理解,或是查阅资料和博客后的总结,多多少少会有错误,请各位dalao斧正。

另外,文中对浮点数的一些基础知识,没有过多的解释,如果对浮点数机制有所疑惑,请参考笔者的另一篇文章:

深入理解Java浮点数机制:深入理解Java浮点数机制【详析】_Return_head的博客-CSDN博客

正文

Java中,经常可以见到类型转换的场景,数据类型转换在Java编码过程中占据着及其重要的地位。对于Java来说,数据类型转换大致可以分为三种,它们分别是:

1.基本数据类型之间的转换;

2.字符串与基本数据类型的转换;

3.引用数据类型之间的转换。

本文主要探讨基本数据类型转换的原理和底层实现。

基本数据类型之间的转换

Java中,共有八种数据类型

byte,short,int,long,char,float,double,boolean

按表示数据类型分类,大致可划分为数值型、字符型和布尔类型。它们具有各自不同的表征范围和底层实现。

如何实现它们的互相转换和正确存储,就成为了一个必须解决的问题。

按照日常编程的习惯,我们可以将基本数据类型之间的转换分为以下三种情况:

1.低级类型到高级类型的自动类型提升;

2.高级类型到低级类型的强制类型转换;

3.包装类的拆装箱。

本文中先抛开包装类的拆装箱问题。主要讨论基本数据类型的自动类型提升和强制类型转换。

在开始探讨类型转换之前,我们首先需要认识一个词语——符号扩展Sign Extension

符号扩展

在编程或者笔试题目中,常常可能遇到这样一种情况。对于一个int类型的数,将其转换为byte类型后,得到的究竟一个正数还是一个负数呢?反之,将一个byte的负数转换为int类型,我们又怎样从底层去判断它最终的符号呢?要理解这两点,我们首先需要了解计算机中数的表示,以及Java中数据的转换方式。

计算机中数的表示

计算机中的数都是以补码的形式存储的,最高位单独作为符号位。正数的补码、反码都等于其二进制原码。而负数的补码等于其原码除去符号位外,按位取反再加1。知道这一点后,我们便能很清楚Java中各种类型的整型数据的范围是怎么得到的了。

举个栗子。我们都知道,Java中byte类型占一字节,8比特位。那么它的取值范围为什么是-128~127呢?

首先,对于byte类型,首位需要作为符号位,若符号位为1,就代表整个数为负数,符号位为0,就代表整个数为正数。其余7位。各能表示0B000_0000~0B111_1111(0~127)这个范围内的128个数。但这就带来了一个问题:当符号位为1或0的时候,各有一个0,即+0和-0。对于数学运算来说,若0的表示有两种,就会使得运算规则复杂化。所以我们就将负0(补码1000 0000)作为一个新的负数,其表示的值,是在原来该类型所能表示的最小负数的基础上再-1所得到的值。对于byte来说,这个值为-128。

至此,我们就得到了byte的取值范围—— -128~127。(以上的过程,适用于所有整型数的范围计算,由于浮点型数据采用了另一种标准,所以其表示范围会有很大差别。)

有了以上的表示后,另一个问题接踵而至:如何在进行类型扩展的时候,保持括号和数字的值不变呢?

Java中的符号扩展(Sign Extension)

什么是符号扩展?

符号扩展,用于在数值类型扩展时扩展二进制的长度,以保证转换后的数值和原数值的符号、以及数值大小相同,一般用于较窄的类型向较宽的类型转换。扩展二进制的长度是指,在原数值的二进制位左边补齐若干个符号位(正数补0,负数补1)。

再举个栗子

(p.s. +15|-15的原码误写成+7|-7了,这里改正一下,同时感谢

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值