为什么Java的+ =, - =,* =,/ =复合赋值运算符需要转换?

时间:2012-01-03 10:10:32

标签: java casting operators variable-assignment assignment-operator

直到今天,我还以为:

i += j;

只是一个捷径:

i = i + j;

但如果我们尝试这个:

int i = 5;
long j = 8;

然后i = i + j;将无法编译,但i += j;将编译正常。

这是否意味着实际上i += j;是这样的捷径 i = (type of i) (i + j)

11 个答案:

答案 0 :(得分:2345)

与这些问题一样,JLS也有答案。在这种情况下§15.26.2 Compound Assignment Operators。提取物:

  

E1 op= E2形式的复合赋值表达式等同于E1 = (T)((E1) op (E2)),其中TE1的类型,但E1仅被评估一次。

§15.26.2

引用的一个例子
  

[...]以下代码是正确的:

short x = 3;
x += 4.6;
     

并导致x的值为7,因为它相当于:

short x = 3;
x = (short)(x + 4.6);

换句话说,你的假设是正确的。

答案 1 :(得分:463)

此演员的一个很好的例子是使用* =或/ =

byte b = 10;
b *= 5.7;
System.out.println(b); // prints 57

byte b = 100;
b /= 2.5;
System.out.println(b); // prints 40

char ch = '0';
ch *= 1.1;
System.out.println(ch); // prints '4'

char ch = 'A';
ch *= 1.5;
System.out.println(ch); // prints 'a'

答案 2 :(得分:240)

非常好的问题。 Java Language specification确认了您的建议。

  

例如,以下代码是正确的:

short x = 3;
x += 4.6;
     

并导致x的值为7,因为它相当于:

short x = 3;
x = (short)(x + 4.6);

答案 3 :(得分:177)

是,

基本上当我们写

i += l; 

编译器将其转换为

i = (int)(i + l);

我刚检查了.class文件代码。

真的很高兴知道

答案 4 :(得分:89)

如果long,您需要从int投射到explicitly i = i + l,然后它会编译并提供正确的输出。喜欢

i = i + (int)l;

i = (int)((long)i + l); // this is what happens in case of += , dont need (long) casting since upper casting is done implicitly.

但是在+=的情况下它只是工作正常,因为运算符隐式地从右变量的类型到左变量的类型进行类型转换,因此不需要显式转换。

答案 5 :(得分:60)

这里的问题涉及类型转换。

添加int和long时,

  1. int对象被转换为long&两者都被添加,你得到长对象。
  2. 但是长对象不能隐式地转换为int。所以,你必须明确地这样做。
  3. 但是+=的编码方式是它可以进行类型转换。 i=(int)(i+m)

答案 6 :(得分:51)

在Java类型中,当赋值操作右侧的表达式类型可以安全地提升为赋值左侧的变量类型时,将自动执行转换。因此我们可以安全地分配:

 byte -> short -> int -> long -> float -> double. 

同样不会反过来。例如,我们不能自动将long转换为int,因为第一个需要比第二个更多的存储,因此信息可能会丢失。为了强制进行这种转换,我们必须进行明确的转换 Type - Conversion

答案 7 :(得分:43)

有时,在面试中可以提出这样的问题。

例如,当你写:

int a = 2;
long b = 3;
a = a + b;

没有自动类型转换。在C ++中,编译上面的代码不会有任何错误,但在Java中你会得到像Incompatible type exception这样的东西。

所以要避免它,你必须像这样编写代码:

int a = 2;
long b = 3;
a += b;// No compilation error or any exception due to the auto typecasting

答案 8 :(得分:21)

主要区别在于a = a + b,没有进行类型转换,因此编译器因为没有进行类型转换而对你生气。但是对于a += b,它真正做的是将b类型转换为与a兼容的类型。所以,如果你这样做

int a=5;
long b=10;
a+=b;
System.out.println(a);

你真正做的是:

int a=5;
long b=10;
a=a+(int)b;
System.out.println(a);

答案 9 :(得分:10)

这里的细微之处......

i+j为双精度且j为整数时,i存在隐式类型转换。 Java ALWAYS 在它们之间有操作时将整数转换为double。

澄清i+=j其中i是一个整数而j是双精度可以被描述为

i = <int>(<double>i + j)

请参阅:this description of implicit casting

为了清楚起见,您可能希望在这种情况下将j强制转换为(int)

答案 10 :(得分:0)

Java语言规范defines E1 op= E2 to be equivalent to be E1 = (T) ((E1) op (E2)) where T is a type of E1 and E1 is evaluated once

这是一个技术性的答案,但您可能想知道为什么是这种情况。好吧,让我们考虑以下程序。

public class PlusEquals {
    public static void main(String[] args) {
        byte a = 1;
        byte b = 2;
        a = a + b;
        System.out.println(a);
    }
}

此程序打印什么?

您猜3吗?太糟糕了,该程序无法编译。为什么?好吧,恰好发生了Java is defined to return an int中字节的增加。我相信这是因为Java虚拟机没有定义要保存在字节码上的字节操作(毕竟,字节码数量有限),而使用整数运算代替的是语言中的实现细节。

但是,如果a = a + b不起作用,则意味着如果a += b被定义为E1 += E2,则E1 = E1 + E2就不会对字节起作用。如前面的示例所示,情况确实如此。作为使+=运算符可以处理字节和短裤的技巧,其中涉及隐式强制转换。这并不是什么骇人听闻的事,但是在Java 1.0工作期间,重点就在于开始发布该语言。现在,由于向后兼容,无法删除Java 1.0中引入的这种黑客攻击。