78

short我对Java 中的原始类型有疑问。我正在使用 JDK 1.6。

如果我有以下情况:

short a = 2;
short b = 3;
short c = a + b;

编译器不想编译 - 它说它“无法从 int 转换为 short”并建议我进行强制转换short,所以这是:

short c = (short) (a + b);

真的有效。但我的问题是为什么我需要投?a 和 b 的值的范围是short- 短值的范围是 {-32,768, 32767}。当我想执行操作时,我还需要强制转换 -、*、/(我没有检查其他人)。

如果我对原始类型做同样的int事情,我不需要将 aa+bb 转换为int. 以下工作正常:

int aa = 2;
int bb = 3;
int cc = aa +bb;

我在设计一个需要添加两个 short 类型变量的类时发现了这一点,编译器希望我进行强制转换。如果我使用两个类型的变量来执行此int操作,则不需要强制转换。

一个小评论:原始类型也会发生同样的事情byte。所以,这有效:

byte a = 2;
byte b = 3;
byte c = (byte) (a + b);

但这不是:

byte a = 2;
byte b = 3;
byte c = a + b;

对于long, float,doubleint, 不需要强制转换。只为shortbyte价值观。

4

11 回答 11

64

正如简短 C#中所解释的(但也适用于其他语言编译器,如 Java)

有一个从 short 到 int、long、float、double 或 decimal 的预定义隐式转换。

您不能将具有较大存储大小的非文字数字类型隐式转换为 short(有关整数类型的存储大小,请参阅整数类型表)。例如,考虑以下两个短变量 x 和 y:

short x = 5, y = 12;

以下赋值语句将产生编译错误,因为赋值运算符右侧的算术表达式默认计算为 int。

short z = x + y;   // Error: no conversion from int to short

要解决此问题,请使用强制转换:

short z = (short)(x + y);   // OK: explicit conversion

但是可以使用以下语句,其中目标变量具有相同的存储大小或更大的存储大小:

int m = x + y;
long n = x + y;

一个很好的后续问题是:

“为什么赋值运算符右侧的算术表达式默认为 int”?

第一个答案可以在以下位置找到:

整数常数折叠的分类和形式化验证

Java 语言规范准确定义了整数如何表示以及如何计算整数算术表达式。这是 Java 的一个重要属性,因为这种编程语言被设计用于 Internet 上的分布式应用程序。Java 程序需要独立于执行它的目标机器来产生相同的结果

相比之下,C(以及大多数广泛使用的命令式和面向对象的编程语言)更加草率,并且留下了许多重要特征。这种不准确的语言规范背后的意图很明确。通过使用目标处理器中内置的算术运算实例化源程序的整数算术,相同的 C 程序应该在 16 位、32 位甚至 64 位架构上运行。这导致代码效率更高,因为它可以直接使用可用的机器操作。只要整数计算只处理“足够小”的数字,就不会出现不一致。

从这个意义上说,C 整数算术是一个占位符,它没有由编程语言规范精确定义,而是通过确定目标机器完全实例化。

Java 精确地定义了如何表示整数以及如何计算整数算术。

      Java Integers
--------------------------
Signed         |  Unsigned
--------------------------
long  (64-bit) |
int   (32-bit) |
short (16-bit) |  char (16-bit)
byte  (8-bit)  |

Char 是唯一的无符号整数类型。它的值表示 Unicode 字符,从\u0000\uffff,即从 0 到 2 16 -1。

如果整数运算符具有 long 类型的操作数,则另一个操作数也将转换为 long 类型。否则,对 int 类型的操作数执行操作,如有必要,较短的操作数将转换为 int。转换规则是精确指定的。

[摘自《理论计算机科学电子笔记》 82 No. 2 (2003)
Blesner-Blech-COCV 2003:Sabine GLESNER , Jan Olaf BLECH,
Fakultät für Informatik,
Universität Karlsruhe
Karlsruhe, Germany]

于 2009-01-25T14:42:31.167 回答
17

编辑:好的,现在我们知道它是 Java ......

Java 语言规范的第 4.2.2 节指出:

Java 编程语言提供了许多作用于整数值的运算符:

[...]

  • 数值运算符,产生 int 或 long 类型的值:
  • [...]
  • 加法运算符 + 和 - (§15.18)

  • 换句话说,它就像 C# - 加法运算符(当应用于整数类型时)只会导致intor long,这就是您需要强制转换以分配给short变量的原因。

    原始答案(C#)

    在 C# 中(你没有指定语言,所以我猜),原始类型的唯一加法运算符是:

    int operator +(int x, int y);
    uint operator +(uint x, uint y);
    long operator +(long x, long y);
    ulong operator +(ulong x, ulong y);
    float operator +(float x, float y);
    double operator +(double x, double y);
    

    这些在 C# 3.0 规范的第 7.7.4 节中。此外,定义了小数加法:

    decimal operator +(decimal x, decimal y);
    

    (枚举添加、字符串连接和委托组合也在这里定义。)

    如您所见,没有short operator +(short x, short y)运算符 - 因此两个操作数都隐式转换为 int,并使用 int 形式。这意味着结果是“int”类型的表达式,因此需要强制转换。

    于 2009-01-25T14:46:09.943 回答
    16

    在 C# 和 Java 中,赋值右侧的算术表达式默认为 int。这就是为什么你需要转换回一个 short 的原因,因为显然没有将 int 形式隐式转换为 short 的原因。

    于 2009-01-25T14:41:27.347 回答
    8

    鉴于尚未回答“为什么默认为 int”的问题...

    首先,“默认”并不是真正正确的术语(尽管足够接近)。正如 VonC 所指出的,由 int 和 long 组成的表达式将产生 long 结果。由整数/日志和双精度数组成的操作将产生双精度结果。编译器将表达式的项提升为在结果中提供更大范围和/或精度的任何类型(浮点类型被假定具有比整数更大的范围和精度,尽管您确实会丢失将大长整数转换为双精度的精度)。

    需要注意的是,此促销仅针对需要它的条款进行。因此,在以下示例中,子表达式 5/4 仅使用整数值并使用整数数学执行,即使整个表达式涉及双精度数。结果出乎你的意料...

    (5/4) * 1000.0
    

    好的,那么为什么 byte 和 short 被提升为 int 呢?没有任何参考支持我,这是由于实用性:字节码数量有限。

    顾名思义,“字节码”使用单个字节来指定操作。例如iadd,它添加了两个整数。目前,定义了 205 个操作码,整数数学对每种类型需要18个(即整数和长整数之间总共 36 个),不包括转换运算符。

    如果很短,并且每个字节都有自己的操作码集,那么您将处于 241,从而限制了 JVM 扩展的能力。正如我所说,没有任何参考资料支持我,但我怀疑 Gosling 等人说“人们实际上多久使用一次短裤?” 另一方面,将 byte 提升为 int 会导致这种不太好的效果(预期答案是 96,实际是 -16):

    byte x = (byte)0xC0;
    System.out.println(x >> 2);
    
    于 2009-01-25T15:55:48.867 回答
    5

    您使用什么语言?

    许多基于 C 的语言都有一个规则,即任何数学表达式都以 int 或更大的大小执行。因此,一旦添加了两条短裤,结果就是 int 类型。这导致需要演员表。

    于 2009-01-25T14:40:20.267 回答
    2

    Java 总是使用至少 32 位的值进行计算。这是由于 1995 年引入 java 时常见的 32 位架构。CPU中的寄存器大小为32位,算术逻辑单元接受2个cpu寄存器长度的数字。因此,CPU 针对这些值进行了优化。

    这就是为什么所有支持算术运算且小于 32 位的数据类型在您使用它们进行计算时都会立即转换为 int(32 位)的原因。

    所以总而言之,它主要是由于性能问题,现在为了兼容性而保留。

    于 2016-05-18T17:11:33.950 回答
    1

    在java中,每个数字表达式都像:

    anyPrimitive zas = 1;
    anyPrimitive bar = 3;
    ?? x = zas  + bar 
    

    如果其中一个加法元素是 long,x 将始终至少为 int 或 long。

    但有一些怪癖很难

    byte a = 1; // 1 is an int, but it won't compile if you use a variable
    a += 2; // the shortcut works even when 2 is an int
    a++; // the post and pre increment operator work
    
    于 2010-05-02T02:43:04.360 回答
    1

    任何低于“int”的数据类型(布尔值除外)都会隐式转换为“int”。

    在你的情况下:

    short a = 2;
    short b = 3;
    short c = a + b;
    

    (a+b) 的结果被隐式转换为 int。现在你将它分配给“short”。所以你得到了错误。

    short,byte,char——对于所有这些我们都会得到同样的错误。

    于 2014-09-26T10:27:24.430 回答
    1

    AFAIS,没有人提到它的final用法。如果您修改最后一个示例并将变量 a 和 b 定义为final 变量,则编译器可以确保它们的总和值 5 可以分配给 type 的变量byte,而不会损失任何精度。在这种情况下,编译器最好将 a 和 b 的总和分配给 c 。这是修改后的代码:

    final byte a = 2;
    final byte b = 3;
    byte c = a + b;
    
    于 2017-01-19T20:04:57.033 回答
    0

    我想补充一些没有被指出的东西。Java 没有考虑您在...中给出的变量(2 和 3)的值

    短 a = 2; 短 b = 3; 短 c = a + b;

    据Java所知,你可以做到这一点......

    短a = 32767;短 b = 32767; 短 c = a + b;

    这超出了short的范围,它将结果自动装箱为int,因为“可能”结果将不仅仅是一个short但不超过一个int。Int 被选为“默认值”,因为基本上大多数人不会硬编码高于 2,147,483,647 或低于 -2,147,483,648 的值

    于 2009-01-30T11:29:29.177 回答
    0

    如果两个值具有不同的数据类型,那么 java 会自动将其中一个值提升为两种数据类型中较大的一个。在您的情况下,较小的数据类型(例如 byte、short 和 char)将在与二进制算术运算符一起使用时被“提升”为 int。如果两个操作数都不是 int,这仍然是正确的。

    short x = 10;
    short y = 20;
    short z = x+y // this will be a compiler error. To solve this then casting would be required
    short z = (short)(x+y) // this will return 30
    short z = (short) x+y //this will return a compiler error
    

    请记住,强制转换是一元运算符,因此通过将较大的值强制转换为较小的数据类型,您实际上是在告诉编译器忽略默认行为。

    于 2021-05-27T11:48:04.823 回答