编程

在 Java 中将 int 转换成 short

95 2024-05-06 22:35:00

1. 概述

使用 Java 时,我们经常会遇到需要转换数据类型以适应特定需求的场景。一种常见的转换是从 int 转换成 short。
本教程中,我们将探讨如何将 int 转换为 short,以及需要注意的潜在陷阱。

2. 问题介绍

Java 提供了几种基本数据类型来存储数值,每种类型都有其范围和精度。例如,int 数据类型是一个 32 位有符号整数,其值范围从 -2 ^ 31 到 2 ^ 31 – 1。另一方面,short 数据类型是一个 16 位有符号整数,可容纳 -2 ^ 15 到 2 ^ 15 – 1 之间的值。
由于 int 的范围比 short 的范围更广,将 int 转换为 short 可能会有潜在的陷阱,我们将在下面的部分中详细讨论。
接下来,让我们探讨一下在 Java 中将 int 转换为 short。

3. 将 int 强制转换成 short

将 int 转换为 short 最简单的方法是强制转换。一个例子可以清楚地说明它是如何工作的:

short expected = 42;
int i = 42;
short result = (short) i;
assertEquals(expected, result);

在 Java 中,整数有两种类型:基元 int 和 Integer。接下来,让我们看看如何将 Integer 实例转换为 short。

4. 使用 Integer.shortValue() 方法

Integer 类提供了 shortValue() 方法。顾名思义,shortValue() 用于将给定的 Integer 转换成 short 值:

short expected = 42;
Integer intObj = 42;
short result = intObj.shortValue();
assertEquals(expected, result);

然而,如果我们看看 shortValue() 方法的实现,就会发现它在内部将 Integer 值强制转换为 short 值

public short shortValue() {
    return (short)value;
}

我们已经注意到,在 Java 中,int 范围大于 short。因此,我们可能会想:如果给定的整数超过了 short 范围,会发生什么?接下来,让我们详细研究一下这一点。

5. 潜在的陷阱

将一个值超过 short 范围的整数强制转换,可能会产生“意外”的结果。接下来,让我们检查几个转换示例:

int oneMillion = 1_000_000;
short result = (short) oneMillion;
assertEquals(16960, result);

本例中,整数值为一百万,超过了 short 的最大值(32767)。强制转换后,它变成了 16960 的 short 值。
此外,如果我们将整数更改为 200 万,我们甚至会得到一个负数(-31616):

int twoMillion = 2_000_000;
result = (short) twoMillion;
assertEquals(-31616, result);

接下来,我们将探讨为什么会出现这些意外的数值。

为了解决这个问题,让我们首先了解在 Java 中,short 是如何表示为二进制数的。

5.1. short: 16 位有符号整数

我们已了解到,short 在 Java 中是一个 16 位有符号整数。最高有效位(MSB)表示整数的符号:0 表示正数,1 表示负数。例如,short 值 42 以这种方式存储:

short 42:
    00000000 00101010
    ^
    MSB

按照这个规则,有些人可能会认为 -42 可以表示为 “10000000 00101010”。然而,事实并非如此:

short -42:
    11111111 11010110
    ^
    MSB

这是因为 Java 使用 2 的补码来表示负数。简单地说,在二的补码计算中,有两个步骤:首先,将每个位反转,然后将反转的二进制数加一。
接下来,让我们了解一下为什么 -42 可以表示为“1111111111010110”:

Binary          : 11111111 11010110 (MSB: 1 -> Negative)
Invert bits     : 00000000 00101001
+ 1             : 00000000 00101010
Decimal         : 42
Result          : -42

现在我们知道了 short 是如何存储的,让我们了解一下如果我们将 int 强制转换为 short 会发生什么。

5.2. 强制转换的工作原理

在 Java 中,int 是一个 32 位有符号整数,比 short 多提供 16 位。因此,当我们将 int 强制转换为 short 时,int 的 16 个高阶位会被截断。
一个例子可以很快阐明这一点。让我们看看当我们将 int 值 42 强制转换为 short 时它是如何工作的:

42 (int)      : 00000000 00000000 00000000 00101010
cast to short :                   00000000 00101010
Result        : 42

现在,我们可以理解为什么当我们将一百万的整数转换为 short 时会得到“意外”的结果。由于 short 的范围比 int 窄,因此在强制转换过程中会丢弃超过 short 容量的高阶位,从而在产生的 short 中产生意外值:

1 million (int)  : 00000000 00001111 01000010 01000000
Cast to short    :                   01000010 01000000
Decimal          :                   16960

在“强制转换两百万的整数”示例中,我们得到了一个负数,因为截断高阶位后 MSB 为 1:

2 million (int)  : 00000000 00011110 10000100 10000000
Cast to short    :                   10000100 10000000
MSB: 1 -> Negative
Invert bits      :                   01111011 01111111
+ 1              :                   01111011 10000000 
Decimal          :                   31616
Result           :                   -31616

5.3. 新建 intToShort()

It’s essential to be cautious when casting int to short, as it can lead to data loss or unexpected behavior if the int value is outside the range of short. We should always check if the int value is between Short.MIN_VALUE and Short.MAX_VALUE before casting:

将 int 强制转换为 short 时必须谨慎,因为如果 int 值超出 short 的范围,可能会导致数据丢失或意外行为。我们应该始终在强制转换之前,检查 int 值是否在 Short.MIN_VALUE Short.MAX_VALUE 之间:

short intToShort(int i) {
    if (i < Short.MIN_VALUE || i > Short.MAX_VALUE) {
        throw new IllegalArgumentException("Int is out of short range");
    }
    return (short) i;
}

然后,当输入整数超出 short 的范围时,它抛出一个异常:

short expected = 42;
int int42 = 42;
assertEquals(expected, intToShort(int42));
 
int oneMillion = 1_000_000;
assertThrows(IllegalArgumentException.class, () -> intToShort(oneMillion));

6. 结论

本文中,我们探讨了如何在 Java 中将 int 转换为 short,并讨论了转换一个值超出 short 范围的 int 时可能存在的陷阱。