原始类型'短' - 用Java编写

时间:2009-01-25 14:30:48

标签: java casting primitive short

我对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的范围内 - 短值的范围是{-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,无需投射。仅适用于shortbyte值。

11 个答案:

答案 0 :(得分:60)

short C#中所述(但也适用于其他语言编译器,如Java)

存在从short到int,long,float,double或decimal的预定义隐式转换。

您无法隐式地将较大存储大小的非平面数字类型转换为较短(有关整数类型的存储大小,请参阅“积分类型表”)。例如,考虑以下两个短变量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”?

第一个答案可以在:

找到

Classifying and Formally Verifying Integer Constant Folding

  

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,
FakultätfürInformatik,
UniversitätKarlsruhe
德国卡尔斯鲁厄]

答案 1 :(得分:17)

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

Section 4.2.2 of the Java Language Specification州:

  

Java编程语言提供   一些行动的经营者   积分值:

     

[...]      

  • 数值运算符,结果如下   在int或long类型的值:   
  • [...]
  • 添加剂运算符+和    - (§15.18)

  • 换句话说,它就像C# - 加法运算符(当应用于整数类型时)只导致intlong,这就是为什么需要强制转换为赋值给short 1}}变量。

    原始答案(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”类型的表达式,因此需要强制转换。

    答案 2 :(得分:16)

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

    答案 3 :(得分:6)

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

    首先,“默认”并不是正确的术语(虽然足够接近)。正如VonC所指出的,由int和long组成的表达式将有很长的结果。由int / logs和double组成的操作将产生双重结果。编译器将表达式的术语提升到任何类型,在结果中提供更大的范围和/或精度(浮点类型被假定具有比积分更大的范围和精度,尽管丢失精度将大长度转换为加倍)。 / p>

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

    (5/4) * 1000.0
    

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

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

    如果short,并且每个字节都有自己的操作码集,那么你将处于241,这限制了JVM扩展的能力。正如我所说,没有提及支持我,但我怀疑Gosling等人说“人们多久经常使用短裤?”另一方面,将byte转换为int会导致这种不那么精彩的效果(预期答案为96,实际为-16):

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

    答案 4 :(得分:5)

    您使用的是哪种语言?

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

    答案 5 :(得分:2)

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

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

    总而言之,这主要是由于性能问题,并且现在保持兼容性。

    答案 6 :(得分: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
    

    答案 7 :(得分:1)

    任何低于" int"的数据类型(布尔除外)隐式转换为" int"。

    在你的情况下:

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

    (a + b)的结果被隐式转换为int。现在你将它分配给"短"。因此你得到了错误。

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

    答案 8 :(得分:1)

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

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

    答案 9 :(得分: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

    答案 10 :(得分: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
    

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