Java 为什么不';t爪哇';s+;=,-=,*=,/=复合赋值运算符需要强制转换吗?

Java 为什么不';t爪哇';s+;=,-=,*=,/=复合赋值运算符需要强制转换吗?,java,casting,operators,variable-assignment,assignment-operator,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=(i的类型)(i+j)?与这些问题一样,JLS持有答案。在这种情况下。摘录: 形式为E1op=E2的复合赋值表达式等价于E1=(T)((E1)op(E2)),其中T是E1的类型,除了E1仅计算一次之外 引自 […]以下代码是正确的: short

直到今天,我还以为例如:

i += j;
这只是一条捷径:

i = i + j;
但如果我们尝试这样做:

int i = 5;
long j = 8;
然后
i=i+j将不编译,但
i+=j可以很好地编译

这是否意味着实际上
i+=j是这样的快捷方式

i=(i的类型)(i+j)

与这些问题一样,JLS持有答案。在这种情况下。摘录:

形式为
E1op=E2
的复合赋值表达式等价于
E1=(T)((E1)op(E2))
,其中
T
E1
的类型,除了
E1
仅计算一次之外

引自

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

short x = 3;
x += 4.6;
short x = 3;
x += 4.6;
结果x的值为7,因为它等于:

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

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

如果是
i=i+l
,您需要将
long
转换为
int
,然后它将编译并给出正确的输出。像

i = i + (int)l;

但是在
+=
的情况下,它工作得很好,因为操作符隐式地执行从右变量类型到左变量类型的类型转换,所以不需要显式转换。

非常好的问题。报告证实了你的建议

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

short x = 3;
x += 4.6;
short x = 3;
x += 4.6;
结果x的值为7,因为它等于:

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

基本上当我们写作的时候

i += l; 
编译器将其转换为

i = (int)(i + l);
我刚刚检查了
.class
文件代码


知道这一点真的是件好事

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

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


这里的问题涉及类型转换

当您添加int和long时

  • int对象被强制转换为long&两者都被添加,得到long对象
  • 但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++中,编译代码不会有任何错误,但是在爪哇中,你会得到一些类似的代码:<代码>不兼容类型异常> />代码>

    因此,为了避免这种情况,您必须这样编写代码:

    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
    为双精度且
    i
    为整数时,存在
    i+j
    的隐式类型转换。 Java始终在整数和双精度之间进行运算时将其转换为双精度

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

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


    在本例中,为了清晰起见,您可能需要将
    j
    键入
    (int)

    Java语言规范

    这是一个技术性的答案,但你可能想知道为什么会这样。好的,让我们考虑下面的程序。
    public class PlusEquals {
        public static void main(String[] args) {
            byte a = 1;
            byte b = 2;
            a = a + b;
            System.out.println(a);
        }
    }
    
    这个程序打印什么

    你猜到3了吗?太糟糕了,这个程序无法编译。为什么?在Java中,字节的加法也是如此。我认为这是因为Java虚拟机没有定义字节操作来保存字节码(毕竟字节码的数量有限),使用整数操作是一种语言中公开的实现细节


    但是如果
    a=a+b
    不起作用,那就意味着
    a+=b
    如果
    E1+=E2
    被定义为
    E1=E1+E2
    就永远不会对字节起作用。正如前面的例子所示,情况确实如此。作为一种让
    +=
    操作符处理字节和短字符的技巧,其中涉及到隐式转换。这不是一个很好的黑客行为,但在Java1.0工作期间,重点是从发布语言开始。现在,由于向后兼容,Java 1.0中引入的这种攻击无法删除。

    在这种情况下,“隐式转换”可能会有损。实际上,正如@LukasEder在他的回答中所说的,转换到
    int
    是在
    +
    之后执行的。如果编译器真的将
    long
    强制转换为
    int
    ,它会(应该?)抛出警告。因此
    i+=j
    在我检查自己时编译,但这会导致精度损失,对吗?如果是这样的话,为什么它不允许它也发生在i=i+j中呢?为什么要在那里打扰我们?@ronnieaka:我猜语言设计者认为在一种情况下(
    I+=j
    ),与另一种情况相比,假设精度损失是需要的更安全(
    I=I+j
    )不,就在那里,就在我面前!对不起,我之前没注意到。在您的回答中,
    E1 op=E2相当于E1=(T)((E1)op(E2))
    ,这有点像隐式向下类型转换(从long向下到int)。而在i=i+j中,我们必须明确地这样做