资讯专栏INFORMATION COLUMN

关于 Java 中的强制类型转换

wind5o / 1122人阅读

摘要:问题描述遇到一个题目经过强制类型转换以后,变量,的值分别为多少答案是这涉及到的,打算借此稍稍研究一下。分为两种,一是扩展型基本数据类型转换,二是窄化型基本数据类型转换。需要注意的是是有可能丢失数值的整体信息以及损失精度和范围的。

问题描述

遇到一个题目:

经过强制类型转换以后,变量a,b的值分别为多少?  
short a = 128;
byte b = (byte) a;
a = ?, b = ?

答案是:a = 128, b = -128

这涉及到 Java primitive type 的 conversion,打算借此稍稍研究一下。

分析过程

下面分析中会涉及到一些与题目无关的细节,想直接看题目解答的请跳到 "题目中的数值在内存中的表示"

明确 Java 中的 Conversion

Java 的 conversion 有多种,这里我们只讨论 primitive conversion。

primitive conversion 分为两种,一是 Widening Primitive Conversion(扩展型基本数据类型转换),二是 Narrowing Primitive Conversion(窄化型基本数据类型转换)。

ps: 翻译成中文还是感觉怪怪的,下面还是用英文表示吧。

1. Widening Primitive Conversion

JLS 定义了 19 种 widening pc,简单来说,就是位数低的向高的转换,如下

byte to short, int, long, float, or double

short to int, long, float, or double

char to int, long, float, or double

int to long, float, or double

long to float or double

float to double

widening pc 不会丢失数值的整体大小信息

2. Narrowing Primitive Conversion

这个问题涉及到的 int -> short 和 short -> byte 的转换就包含在 JLS 定义的 22 种 narrowing pc 之中。

short to byte or char

char to byte or short

int to byte, short, or char

long to byte, short, char, or int

float to byte, short, char, int, or long

double to byte, short, char, int, long, or float

需要注意的是 narrowing pc 是有可能丢失数值的整体信息以及损失精度和范围的。

可能有人会注意到,上面的 widening pc 和 narrowing pc 都没有包含 byte -> char 的转换

Chapter 5. Conversions and Promotions

The following conversion combines both widening and narrowing primitive conversions:
byte to char
First, the byte is converted to an int via widening primitive conversion (§5.1.2), and then the resulting int is converted to a char by narrowing primitive conversion (§5.1.3).

这是因为这是一种特殊地、同时结合了 widening pc 和 narrowing pc 的转换,byte 会先转换成 int(widening pc),然后将这个 int 结果转换成 char(narrowing pc)。

具体分析

那么我们还是回到这个问题

short a = 128; 
byte b = (byte) a;

首先,在 Java 中,整数默认为 int 类型,也就是说,在 short a = 128; 中,会发生 int -> short 的 narrowing pc,是有可能损失精度的,由于 int 是高位(32位),short 是低位(16位),所以在转换时会 truncate。同样,对于 byte b = (byte) a; 也有可能因为 truncate 而损失精度。

先回顾原码、反码、补码的概念

在 Java 中数值是用补码表示的,在这里回顾一下原码、反码、补码的概念(以 3 为例吧):

原码(第一个为符号位,1 表示负数,0 表示正数)

3 的原码:0000 0011

-3 的原码:1000 0011

反码(就是反过来,注意符号位不变):

3 的反码:1111 1100

-3 的反码:1111 1100

补码(正数的补码 = 原码,负数的补码 = 反码 + 1)

3 的补码:0000 0011

-3 的补码:1111 1101

题目中的数值在内存中的表示

二进制表示:

int a = 128 00000000 00000000 10000000 00000000

short a = 128 00000000 10000000 (强转后前面 16 位被截断)

可以看出来,a 的值输出应该还是 128

那么对于 byte b = (byte) a;

二进制表示:

short a = 128 00000000 10000000

byte b = 128 10000000 (强转后前面 8 位被截断)

但是,输出的 b 的值为什么不是 128 而是 -128 呢

Primitive Data Types (The Java™ Tutorials > Learning the Java Language > Language Basics)

byte: The byte data type is an 8-bit signed two"s complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive). The byte data type can be useful for saving memory in large arrays, where the memory savings actually matters. They can also be used in place of int where their limits help to clarify your code; the fact that a variable"s range is limited can serve as a form of documentation.

这是因为 byte 是一个 8 位有符号二进制补码整数,它包含的值的范围是 [-128, 127],因此 byte 类型的值是无法表示 128 的

那么在发生截断后,1000 0000 表示的就是一个补码,从这个补码可以看出来它的原码肯定是一个负数,那么我们根据这个补码反推得到它的反码:1111 1111,从而得到它的原码:1000 0000,可以看出这个值就是 -0,但是在我们的生活中是没有 -0 的,所以在计算机中就把它识别成 -128,因此这就是为什么 b 的值的输出是 -128 的原因。

ps: 关于 -0 对应于 -128 的具体解释,我懒得写了,因为感觉取决于个人的理解,不想细究,如果有人还有疑问,可以看看这个人的解释 byte类型取值范围为什么是127到-128? - 知乎

那么到这里,问题就基本解释清楚了,感觉自己还是很啰嗦,不过其实是为了回顾一些基础的知识,也希望对其他人有所帮助啦~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/69394.html

相关文章

  • 关于java中的强制类型转换和二进制表示问题

    摘要:中用补码形式表示第一位正负位,表示负,表示正。原码一个数的二进制表示。的补码是的补码是占个字节,位占个字节,位所以强转时会截断。 showImg(https://segmentfault.com/img/bVbsydY?w=993&h=471); 1、Java中用补码形式表示2、第一位正负位,1表示负,0表示正。3、原码:一个数的二进制表示。 3的原码0000...

    cyixlq 评论0 收藏0
  • 基本类型类型转换(隐式类型转换)和强制类型转换(译一)

    摘要:基本类型的类型转换和强制类型转换一的变量类型分为种。目录基本类型的类型转换隐式类型转换基本类型的强制类型转换基本类型的类型转换隐式类型转换基本类型的类型转换是通过扩展转换的规则完成的。 基本类型的类型转换和强制类型转换(一) Java的变量类型分为2种。基本类型(原始类型)和引用类型。基本类型包括以下八种类型:boolean、 char、byte、short、int、long、floa...

    pcChao 评论0 收藏0
  • 栈和队列 - Algorithms, Part I, week 2 STACKS AND QUEUE

    摘要:在改进前使用数组的一个缺点是必须声明数组的大小,所以栈有确定的容量。待解决的问题建立一个能够增长或者缩短到任意大小的栈。下边的图是观察时间开销的另一种方式,表示了入栈操作需要访问数组的次数。 前言 上一篇:算法分析下一篇:基本排序 本篇内容主要是栈,队列 (和包)的基本数据类型和数据结构文章里头所有的对数函数都是以 2 为底关于性能分析,可能还是需要一些数学知识,有时间可以回一下在很多...

    Stardustsky 评论0 收藏0
  • 多态

    摘要:父类型引用指向子类型对象多态以下程序编译是没有问题的,因为编译器检查到的数据类型是和之间存在继承关系,并且是父类型,是子类型,父类型转换成子类型叫做向下转型,语法合格。 package duotai;public class Animal { public void move() { System.out.pr...

    Magicer 评论0 收藏0
  • 1.java数据类型

    摘要:虽然定义了这种数据类型,但是只对它提供了非常有限的支持。数据类型的自动转换规律数据范围小的类型与数据范围大的类型进行数学计算的时候,自动向数据范围大的类型转换数据范围大的类型想要变为数据范围小的类型,必须采用强制类型转转。 java数据类型 java一共分为两大类数据: 基本数据类型(值类型) 引用数据类型 基本数据类型 基本数据类型一共有八种,分为:数值型: 整型: byte、s...

    dunizb 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<