基本类型“ short”-Java中的强制转换


78

我对shortJava中的原始类型有疑问。我正在使用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类型的变量,并且编译器希望我进行强制类型转换。如果使用两个type类型的变量来执行此操作int,则不需要强制转换。

一句话:原始类型也会发生相同的情况 byte。因此,这可行:

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

但这不是:

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

对于longfloatdouble,和int,也没有必要投。仅用于shortbyte值。

Answers:


64

正如上文短C# (也为其他语言编译器以及Java一样)

预定义的隐式转换是从short到int,long,float,double或小数。

您不能将较大存储大小的非文字数字类型隐式转换为短类型(有关整数类型的存储大小,请参阅“整数类型表”)。例如,考虑以下两个短变量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卷第2期(2003年),
Blesner-Blech-COCV 2003年:Sabine GLESNER,Jan Olaf BLECH,
德国信息技术
大学,卡尔斯鲁厄大学,
卡尔斯鲁厄,]


T a, b; a += b等效于T a, b; a = (T) (a + b):注意编译器添加的强制转换。
wchargin

17

编辑:好的,现在我们知道它是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#3.0规范的简单超链接版本。MSDN版本太痛苦了IMO :(
    Jon Skeet

    现在我们知道它是Java,因此没有uint或ulong。我不记得Java是否为BigInteger和/或BigDecimal重载了运算符+
    -finnw

    仍为0 ?!来吧... +1,您确实提到了正确的规格;)您能否在我的回答中看看我的后续问题,看看您是否对该主题有一些了解?(即“为什么默认为int? “)
    VonC


    16

    在C#和Java中,赋值右侧的算术表达式默认情况下计算为int。这就是为什么您需要强制转换为short的原因,因为出于明显的原因,没有隐式转换形式将int转换为short。


    8

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

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

    一个警告是,此促销仅针对需要的条款进行。因此,在下面的示例中,子表达式5/4仅使用整数值,并且使用整数数学执行,即使整个表达式包含双精度型。结果并非您所期望的...

    (5/4) * 1000.0
    

    好的,为什么字节和短字符提升为int?由于缺乏实用性,因此没有任何参考资料支持我:字节码数量有限。

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

    如果short和byte每个都有自己的一组操作码,则您将处于241,从而限制了JVM扩展的能力。就像我说的那样,没有提及支持我,但是我怀疑Gosling等人说:“人们实际使用短裤的频率是多少?” 另一方面,将byte提升为int会导致这种不太好的效果(预期答案为96,实际值为-16):

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

    预期的答案是48,不是吗?
    mafu 2013年

    @mafu是的。因此>>强制转换为int?? 但是,效果就是Z80中所谓的SRA(向右算术移位),它将字节的位向右移1位,丢失最右边的位并复制最左边的位(因此将有符号字节除以2),而不是SRL(逻辑右移),它在左侧保留一个零位(与将无符号字节除以2相同),这是“预期答案”的基础。
    Heimdall

    5

    您使用什么语言?

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


    2

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

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

    因此,归纳起来主要是由于性能问题,并且为了兼容性一直保留至今。


    1

    在Java中,每个数值表达式都类似于:

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

    x总是至少为int,或者如果加法元素之一为long则为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
    

    1

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

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

    不完全是。final byte a = (byte) (new Random().nextInt(4));Incompatible types再次抬起丑陋的头。这不仅是最终性,还可以将其编译为适合该类型的值。
    LAFK说恢复莫妮卡

    告诉您对赫伯特·希尔德(Herbert Schildt)的抱怨,这是他的主意。@LIttleAncientForestKami
    snr

    如果我有一个@snr,我会这样做,尤其是因为什至Shildt都无法帮助对抗javac。;-)您的言论暗示着可以final 保证编译器,可能还不够。如果我们以您的逐字记录为例,那么一切都很好。但是,尝试更换b = 3b = (byte)(new Random().nextInt(4))。并且返回不兼容的类型,并且a + b需要再次强制转换。您可能需要将其添加到答案中。
    LAFK说恢复莫妮卡

    1

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

    在您的情况下:

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

    (a + b)的结果隐式转换为int。现在,您将其分配给“ short”。这样您就会收到错误。

    short,byte,char-对于所有这些,我们将得到相同的错误。


    0

    我想添加一些尚未指出的内容。Java没有考虑您在...中给变量(2和3)赋予的值。

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

    就Java所知,您可以做到这一点...

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

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


    废话,因为我可以添加两个int MAXVALUE,并且不需要LHS很长。
    Gordon
    By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
    Licensed under cc by-sa 3.0 with attribution required.