繁体   English   中英

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

[英]Why don't Java's +=, -=, *=, /= compound assignment operators require casting?

直到今天,我认为例如:

i += j;

只是一个捷径:

i = i + j;

但是如果我们试试这个:

int i = 5;
long j = 8;

然后i = i + j; 不会编译但i += j; 会编译得很好。

这是否意味着实际上i += j; 是这样的快捷方式i = (type of i) (i + j)吗?

与这些问题一样,JLS 拥有答案。 在这种情况下, §15.26.2 复合赋值运算符 摘录:

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);

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

这种转换的一个很好的例子是使用 *= 或 /=

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'

很好的问题。 Java 语言规范确认了您的建议。

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

 short x = 3; x += 4.6;

并导致 x 的值为 7,因为它等价于:

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

是的,

基本上当我们写

i += l; 

编译器将其转换为

i = (int)(i + l);

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

知道这真是一件好事

i = i + l情况下,您需要从long explicitlyint然后它将编译并提供正确的输出。 喜欢

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.

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

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

当你添加 int 和 long 时,

  1. int 对象被转换为 long 并且两者都被添加并且你得到了 long 对象。
  2. 但不能将 long 对象隐式转换为 int。 所以,你必须明确地做到这一点。

但是+=的编码方式是进行类型转换。 i=(int)(i+m)

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

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

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

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

例如,当你写:

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

主要区别在于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);

这里的微妙之处...

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

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

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

参见: 隐式转换的这个描述

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

Java 语言规范E1 op= E2定义为等效于E1 = (T) ((E1) op (E2)) ,其中TE1的类型,并且E1被评估一次

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

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

这个程序打印什么?

你猜到3了吗? 太糟糕了,这个程序不会编译。 为什么? 好吧,碰巧在 Java 中添加字节被定义为返回一个int 我相信这是因为 Java 虚拟机没有定义字节操作来保存字节码(毕竟数量有限),而是使用整数操作是一种语言中公开的实现细节。

但是,如果a = a + b不起作用,则意味着如果E1 += E2被定义为E1 = E1 + E2a += b永远不会对字节起作用。 正如前面的例子所示,情况确实如此。 作为使+=运算符适用于字节和短裤的技巧,涉及到隐式转换。 这不是什么了不起的黑客,但在 Java 1.0 工作期间,重点是让语言发布开始。 现在,由于向后兼容,Java 1.0 中引入的这个 hack 无法删除。

暂无
暂无

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

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