编程

在 Java 中将 int 转换成 short

371 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() 函数

将 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 时可能存在的陷阱。