繁体   English   中英

原始类型“short” - 在 Java 中进行转换

[英]Primitive type 'short' - casting in Java

我有一个关于 Java 中的基本类型short的问题。 我正在使用 JDK 1.6。

如果我有以下几点:

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

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

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

真的有效。 但我的问题是为什么我需要投射? a 和 b 的值在short范围内 - 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;

对于longfloatdoubleint ,不需要强制转换。 仅适用于short值和byte值。

简短的 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 字符,从\\￿ ,即从 0 到 2 16 -1。

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

【摘自计算机理论电子笔记82第2期(2003)
Blesner-Blech-COCV 2003: Sabine GLESNER 、Jan Olaf BLECH、
Fakultät für Informatik,
卡尔斯鲁厄大学
德国卡尔斯鲁厄]

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

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

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

[...]

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

  • 换句话说,它就像 C# - 加法运算符(当应用于整数类型时)只会导致intlong ,这就是为什么您需要强制转换以分配给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”类型的表达式,因此需要进行转换。

    在 C# 和 Java 中,赋值右侧的算术表达式默认计算为 int。 这就是您需要转换回 short 的原因,因为出于显而易见的原因,没有从 int 到 short 的隐式转换。

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

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

    需要注意的是,此促销活动仅适用于需要它的条款。 因此,在下面的示例中,子表达式 5/4 仅使用整数值并使用整数数学执行,即使整个表达式涉及双精度。 结果不是你所期望的......

    (5/4) * 1000.0
    

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

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

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

    byte x = (byte)0xC0;
    System.out.println(x >> 2);
    

    你使用什么语言?

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

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

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

    所以总结起来主要是由于性能问题,现在为了兼容性而保留。

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

    在你的情况下:

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

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

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

    在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
    

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

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

    我想补充一些尚未指出的内容。 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

    如果两个值具有不同的数据类型,那么 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
    

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

    暂无
    暂无

    声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

     
    粤ICP备18138465号  © 2020-2024 STACKOOM.COM