知道为什么我需要在此处将整数转换为(int)吗?


122

在下面的例子中

int i = -128;
Integer i2 = (Integer) i; // compiles

Integer i3 = (Integer) -128; /*** Doesn't compile ***/

Integer i4 = (Integer) (int) -128; // compiles
Integer i4 = -128; // compiles
Integer i5 = (int) -128; // compiles
Integer i6 = (Integer) (-128); // compiles
Integer i7 = (Integer) 0-128; // compiles

我不能-128(Integer),但我可以投(int) -128

我一直以为-128是的int类型,将其强制转换(int)应该是多余的。

与线上的错误i3

cannot find symbol variable Integer

我在Java 6 Update 29和Java 7 Update 1中进行了尝试。

编辑:你有获得相同的行为+128,而不是-128。一元运算符和二元运算符之间确实存在混淆。


5
你的编译器是什么?Integer i = -128;不过应该编译。
2011年

怪异的,Integer i3 = (Integer) (-128);虽然顺从。
Enu.Fouad 2011年

2
@ Eng.Fouad,Peter,一元符号(+-)具有从右到左的关联性,加号和减号从左到右。-128的效果与+128相同,并且应该将0放在前面,即0-128或0 + 128。(无法测试自动
取款机,

好问题!我个人希望看到有关一元/二元运算符解析以及将强制转换视为表达式时使用的JLS参考。否则,其他编译器可能不会将其视为错误!
Bringer128 2011年

1
同样,仅供参考,我在IDE中遇到的错误也就在Expression expected这里Integer
Bringer128 2011年

Answers:


151

编译器试图减去128(Integer)代替铸造-128Integer。添加()修复

Integer i3 = (Integer) -128; // doesn't compile
Integer i3 = (Integer) (-128); // compiles

根据BoltClock的评论,强制转换 int按预期工作,因为它是保留字,因此不能解释为标识符,这对我来说很有意义。

Bringer128找到了JLS参考15.16

 CastExpression:
    (PrimitiveType Dims opt)一元表达式
    (ReferenceType)UnaryExpressionNotPlusMinus

如您所见,强制转换为基本类型需要任何UnaryExpression,而强制转换为引用类型需要UnaryExpressionNotPlusMinus。它们在JLS 15.15的CastExpression之前定义。


31
我认为这是因为intJava中有一个关键字,但Integer不是。由于int是关键字,因此不能将其用作变量或类的标识符,而将剩下的唯一可能性保留为类型转换。那就解释了。
BoltClock

@BoltClock将您的评论纳入答案。
詹斯·绍德

3
为了使这个问题更加出色,您是否要将我的链接添加到JLS?
Bringer128 2011年

3
对我而言,一个有趣的皱纹是我们如何解决C#中的类似问题,该问题在“用括号括起来的表达式作为二进制减法运算符的操作数”和“ cast运算符”之间的语法上也存在歧义。强制转换是一元减表达式”。请参阅C#规范的7.7.6节,以详细描述我们用来尝试和巧妙解决歧义的启发式方法。
埃里克·利珀特

1
@BillK为什么这么说?C#规范在第7.7.6节中未涉及运算符重载,因此这对他们而言不是问题。
Bringer128 2011年

48

我找到了JLS参考。15.16

 CastExpression:
    (PrimitiveType Dims opt)一元表达式
    (ReferenceType)UnaryExpressionNotPlusMinus

如您所见,强制转换为基本类型需要任何UnaryExpression,而强制转换为引用类型需要UnaryExpressionNotPlusMinus。它们在JLS 15.15的CastExpression之前定义。

您需要将强制类型更改为原始类型:

... (int) -128;

或者,您可以将演员表右侧的表达式更改为非负一元表达式:

... (Integer) (-128);  // Either
... (Integer) 0 - 128; // Or

12

编译器将解释-为2减号运算符,即它正在尝试从名为Integer,但范围内没有此类变量。

这样编译:

Integer i3 = (Integer) (-128)

您可以添加注释说明为何(int)有所作为。
彼得·劳瑞

1
这是由于自动装箱,不是吗?
Brian Roach

9

这可能与语法分析有关。注意

Integer i4 = (Integer) (-128); 

效果很好。

通常,您不应该转换为Integer类。这涉及一种称为自动装箱的事情,并且可能在代码中引起一些细微的错误。做您想要做的事的首选方法是:

Integer i6 = Integer.valueOf(-128)

1
强制转换为Integer的是valueOf的合成糖。
bestsss 2011年

4
是的,但有时合成糖会以微妙的方式失效。由于自动装箱,我在大型应用程序中很难跟踪空指针异常。为了避免将来的麻烦,我们将自动装箱视为错误。魔术很好,但是当失败时,头部受伤。我发现最好是露骨,并省掉自己的头痛。
Krystian Cybulski

NPE是带发件箱的,是真的。像for (int i in Collection<Integer>)b / c 这样的Esp案例 NPE位于绝对意外的位置。我实际上不使用带自动装箱的Integer w / autoboxing,因为缓存范围很小(尽管可以使用XX选项增加它),但是我有一个名为IntegerProvider的类(从1.1开始)来做同样的事情。使用Map(来自java.util的任何内容)Integer-> Anything通常会降低性能,除非将其用于琐碎的情况下并且几乎总会有更好的解决方案。
2011年

将int强制转换为Integer 永远不会导致任何错误,除非堆溢出。相反,事实并非如此。
Ingo

@MattBall,我不太了解,合成糖被广泛使用:eggcorns.lascribe.net/forum/viewtopic.php?id = 4400,合成听起来对我来说更好。
bestsss 2011年

9

它将其解析为Integer <minus operator> 128并且没有找到变量Integer。您需要将-128方括号括起来:

Integer i3 = (Integer) (-128);  // compiles

我为所有其他答案都授予+1,因为它们也都是正确的:)
Bohemian


6

第3行的解释方式就像您要从括号中的表达式中减去128,而括号中的表达式不是并且int类型的表达式(它将'-'视为'-'运算符)一样。如果将表达式更改为:

Integer i3 = (Integer) (-128);

那么编译器将理解“-”是一元减号,表示负整数。


3

C#编译器具有相同的行为。它提供了更好的提示,但为什么它无法编译:

要强制转换为负值,必须将该值括在括号中

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.