Java中 a=a+b 和 a+=b 的区别

本文探讨了a+=b与a=a+b在Java中的差异,重点在于+=运算符的强制类型转换特性。通过实例说明,在不同数据类型间使用+=时,编译器会自动进行类型转换,而直接赋值则需要显式的类型转换。此外,文章还涉及了浮点数精度问题及小数浮点数的二进制表示。

千万不要放过任何一个小的知识点(一个这么小的点也可以拿来写一篇文章 哈?)

首先网传 a+=b 的效率会比 a=a+b 的效率要高一点,但是我验证了一下,好像并没有这回事。运行 1000000000 次 a=a+1的时间和 a+=1的时间几乎差不多,而且有时候前者快,有时候后者快。这里就不讨论效率高低这个区别了。

说一下另外一个很显著的区别: += 这个运算中包含了强制转换的操作。所以当我们把两个不同类型的变量使用 += 操作的时候,其实编译器已经自动帮我们强制转型了。而 =+ 并没有自动转型,所以如果我们没有手动强制转型的话,编译的时候是会报错的。

看一下测试代码:

public class PlusEqual {
    static char a = 1;
    static int b = 3;
    public static void main(String[] args) {
        a += b;
        a = a + b;//(char)(a + b);
    }
}

现在我们编译的话,是会报错的:

错误: 不兼容的类型: 从int转换到char可能会有损失
        a = a + b;

因为此时a+b此时得到的结果是int,不能直接赋给 char 型的 a。需要强制转型成 a = (char)(a + b);

要记住两点:

一、运算过程中,低精度的类型向高精度类型转换。
二、如果将高精度的数值赋值给低精度类型变量,则必须要进行显性的强制转换。


课外阅读:关于小数浮点数精度的问题

你猜 System.out.println(0.1 * 3); 打印出来的结果是什么?对,是 0.30000000000000004。这就是我们要讨论的小数浮点数的精度问题,而整数浮点数没有精度这个问题。为啥子呢?

先说整数为啥没有这个问题,其实不管是小数还是整数,计算机都是使用二进制存储的。例如 3 用二进制可以表示为 11。因为 2^0 = 1, 2^1 = 2,就这两,我一个一个往上怼,就可以表示一切整数了,对吧,我就不证明了啊哈哈(不会)。

但是小数呢? 2^-1 = 0.5 , 2^-2 = 0.25。由于 double 的长度是64位,其中符号位S占1位,阶码e占11位,尾数M占52位。最终浮点数可以表达为:(-1)^S * M * 2(e)。这样能精确表达的出来的小数其实是有限的,比如 0.25可以直接表达成:(-1)^0 * 1.000000000000 * 2^(-2)。但是0.3这种小数呢?很显然是无法精确表达的,只能通过近似表达,精确到小数点后的16位。

这样也引申出了一个题目哟:3 * 0.1 == 0.3 将会返回什么?true 还是 false?


THE END.

<think> 我们分析表达式:a=9+b=a+7 这个表达式在编程中是否合法,取决于编程语言的规则,尤其是赋值运算符的规则。 步骤1:分解表达式 表达式包含两个赋值运算符(=一个加法运算符(+)。赋值运算符是右结合的,所以表达式相当于: a = ( (9 + b) = (a + 7) ) 步骤2:检查赋值运算符的左侧 赋值运算符要求左侧必须是一个可修改的左值(lvalue)。在子表达式 `(9 + b) = (a + 7)` 中,左侧是 `9+b`。 但是,`9+b` 是一个算术表达式,其结果是一个临时值(右值),它不是一个左值,因此不能放在赋值运算符的左侧。 步骤3:类比之前的问题 在之前的问题中,表达式 `a=b++=a+7` 的错误在于 `b++` 的结果是一个右值,不能作为赋值操作的左操作数。同样,这里 `9+b` 是一个右值,因此也不能作为赋值操作的左操作数。 步骤4:编译器行为 编译器会检测到这种错误并报错。例如,在C/C++中,错误信息可能是:“error: lvalue required as left operand of assignment”。 步骤5:正确写法 如果意图是先计算 `a+7`,然后将结果赋给 `b`,再将 `9+b` 的结果赋给 `a`,那么应该写成两个语句: b = a + 7; a = 9 + b; 或者如果一定要写在一个表达式里,可以考虑使用逗号运算符(但这样可读性较差): a = (b = a + 7, 9 + b); 注意:在支持多重赋值的语言中(如Python),但要注意Python中赋值语句不能出现在表达式内部(除了海象运算符:=,但这里也不适用)。所以上述写法在Python中也是不合法的。 结论:表达式 `a=9+b=a+7` 在大多数编程语言(如C, C++, Java, C#等)中都是非法的,因为赋值运算符的左侧必须是左值,而 `9+b` 不是左值。 引用之前的相关知识: 引用[1][2]讨论了`a+=b``a=a+b`的区别,但这里不涉及这种复合赋值。 引用[3]提到了表达式中的副作用未定义行为,但这里的问题不是未定义行为,而是语法错误。 引用[4]解释了左值的概念,强调了左值必须是一个可以定位的内存位置(location)。 因此,表达式是错误的。 相关问题: 1. 什么是左值(lvalue)右值(rvalue)? 2. 在编程语言中,赋值运算符的左侧允许出现哪些类型的表达式? 3. 如何正确实现多重赋值? </think> ### 表达式 `a=9+b=a+7` 的正确性分析 **该表达式在编程中是错误的**,原因如下: #### 1. **语法解析问题** 赋值运算符 `=` 是**右结合**的,表达式会被解析为: ```c a = ( (9 + b) = (a + 7) ) ``` 但 `9 + b` 是算术表达式的结果,属于**右值(rvalue)**,而赋值运算符 `=` 的左侧**必须是左值(lvalue)**[^4]。 #### 2. **左值要求违反** - **左值(lvalue)** 要求: - 必须是具名变量(如 `a`, `b`) - 必须有可修改的内存地址(如数组元素 `arr[0]`) - **右值(rvalue)** 问题: - `9 + b` 是临时计算结果,无内存地址 - 不能作为 `=` 的左操作数 错误位置明确标记: ``` a = ( (9 + b) = (a + 7) ) ↑ 非法赋值目标(右值) ``` #### 3. **编译器报错示例** 实际编译会报错(以 C/C++ 为例): ```bash error: lvalue required as left operand of assignment ``` #### 4. **对比合法操作** ✅ 正确写法 1(分步赋值): ```c b = a + 7; // 先赋值给左值 b a = 9 + b; // 再计算赋值 ``` ✅ 正确写法 2(避免右值赋值): ```c a = 9 + (b = a + 7); // b 是左值,合法(部分语言支持) ``` > ⚠️ 注意:写法 2 在 Python 等语言中非法(赋值非表达式),在 C/C++ 中合法但有风险(依赖运算顺序)[^3]。 --- ### 关键概念:左值(lvalue) vs 右值(rvalue) | **特性** | **左值 (lvalue)** | **右值 (rvalue)** | |----------------|-------------------------|-------------------------| | **定义** | 可定位的内存位置[^4] | 临时计算结果 | | **能否赋值** | ✅ 可作为 `=` 左侧 | ❌ 不可作为 `=` 左侧 | | **示例** | `x`, `arr[0]`, `*ptr` | `x+5`, `func()`, `3` | --- ### 总结 - **核心错误**:`9 + b` 是右值,违反赋值运算符的左值要求 - **根本原因**:赋值操作左侧必须是可修改的内存位置 - **修复原则**:确保 `=` 左侧始终是变量或可寻址表达式 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值