资讯详情

Java运算符与表达式全解析:优先级、求值顺序与类型转换

📅 2026/10/10 21:28:49 | 华诺云谱 👁 阅读
Java运算符与表达式全解析:优先级、求值顺序与类型转换
1. 运算符与表达式先搞懂它们在Java里到底扮演什么角色Java的运算符和表达式说穿了就三件事怎么算数、怎么比较、怎么赋值。但你要是只背住那张优先级表遇到真正项目里的坑一样会摔得鼻青脸肿。我见过不少工作一两年的开发写a和a倒背如流但一碰到i 1和i i 1在类型转换上的差别就懵了还有人在公司的代码评审会上因为一个比较两个Integer对象判断相等被老同事当众指出来场面相当尴尬。这个主题适合所有人准备Java面试的应届生刚入门编程的在校生还有那些功力不深但天天跟业务代码打交道的后端开发。运算符和表达式不是你背完就完事的知识点它是一套“求值规则”换句话说你写的每一行赋值、每一次判断、每一个三元表达式背后都是一次完整的表达式求值过程。搞懂它你调试代码的速度能快一倍写出来的代码也不容易埋雷。这篇东西不打算按教科书的方式给你念一遍优先级表那玩意儿网上到处都是。我换个思路从实际开发会碰到的真实问题切入带你一步步拆解运算符的底层逻辑、表达式的求值顺序、类型转换的坑以及面试高频题背后的原理。看完之后你可以直接拿这些结论去检查自己项目的代码大概率能发现几个潜在问题。2. 一套划分体系把14类运算符安排得明明白白2.1 按“目数”理解一元、二元、三元运算符Java里的运算符数量不少官方文档能给你列出几十个。但你别被数量吓到先按“需要几个操作数”来分立马清晰一元运算符只操作一个表达式比如-5、!flag、count、(int) x。二元运算符操作两个表达式绝大部分运算符都属于这一类比如a b、x y、c d。三元运算符Java里只有一个就是条件 ? 值1 : 值2三个操作数参与。按目数分类是理解表达式求值的第一步。为什么因为一元运算符的优先级天然高于大部分二元运算符比如-a * b实际是先对a取负再做乘法而不是-(a * b)的另一种写法。这类问题你写几年代码可能都遇不到但一旦遇到就知道为什么加括号永远比记优先级可靠了——后面我会专门说括号的事。2.2 按功能划分算术、赋值、关系、逻辑、位运算等按功能分是日常开发中最常用的划分方式。这里先给大家一张全景表后面每个类别我会单独展开讲关键细节类别代表运算符典型使用场景最容易踩的坑算术运算符 - * / % --数值计算、计数、取模整数除法直接舍去小数、%的结果符号赋值运算符 - * / %变量更新、累加统计复合赋值隐含强制类型转换关系运算符 !条件判断、循环控制引用类型用比较地址而非内容逻辑运算符 || !多条件组合判断短路求值导致部分代码没执行位运算符 | ~ ^ 权限控制、状态压缩、性能优化优先级低于必须加括号三元运算符? :简化if-else赋值两侧类型不一致引发自动类型提升类型比较instanceof运行时类型检查编译期就能确定不可能的类型会直接报错光看这张表还不够。很多人的误区是“我记住了运算符就会写表达式了”实际上运算符只是零件表达式才是成品。表达式可以由运算符、操作数、方法调用、字面量等组合而成求值的结果可能是值、变量甚至什么都不是比如只执行副作用。下一节我重点讲表达式求值这件事这才是我认为真正的核心。3. 表达式求值优先级、结合性和求值顺序到底谁说了算3.1 你对“优先级”的直觉可能在第一层不少人对优先级的印象停留在“先乘除后加减”。到了Java里很多运算符的优先级其实有更细致的划分。举个真实的例子boolean result (flags 0xFF) 0xFF;如果你不主动加括号直接写flags 0xFF 0xFF编译都不会报错但结果完全不对因为的优先级高于实际会被解析成flags (0xFF 0xFF)也就是把flags和一个boolean做按位与逻辑直接崩了。这种问题在C、C、Java里只要写位运算相关的代码就很容易发生。我的经验是位运算符和逻辑运算符混用的时候一律加括号不要相信自己的记忆。Java的优先级表网上到处都有我不完整抄一遍但把很容易被忽略的几层拎出来最高档位后缀运算符也就是array[i]、obj.method()、a这类其次是a这种前缀一元运算符。强制类型转换(type)也属于一元运算符那一档它比算术运算符高。移位运算符 的优先级比加减法低比关系运算符高。很多人写size 2 1会误以为是(size 2) 1实际是先计算2 1再左移3位。逻辑与高于逻辑或||但两者都低于关系运算符。所以a || b c实际是a || (b c)而不是(a || b) c。你以为短路顺序没问题但如果b计算会抛异常这个细节就关键了。3.2 结合性从左到右还是从右到左不是拍脑袋定的结合性解决的是“优先级相同的时候先算谁”的问题。大部分二元运算符是左结合也就是从左往右算int result 100 / 10 * 5; // 结果是50不是2因为/和*优先级相同左结合就是(100 / 10) * 5。然而有一类运算符是右结合一元运算符、赋值运算符、三元运算符。赋值运算符的右结合非常好理解int a, b, c; a b c 10;这个表达式能编译能运行就是因为右结合使得求值顺序是a (b (c 10))。再比如三元运算符右结合意味着条件1 ? 值A : 条件2 ? 值B : 值C会先解析成条件1 ? 值A : (条件2 ? 值B : 值C)。这种写法能链式判断但我个人还是建议就算理解了右结合嵌套三元也最好拆开写或者用括号明确。因为代码是写给人看的不是写给编译器看的。3.3 求值顺序左到右逐个算但短路运算符不讲武德优先级和结合性决定的是“谁先和谁结合”但同一表达式中各个操作数的求值顺序一般是从左到右。比如int result methodA() methodB() * methodC();这里虽然*优先级高会先决定methodB() * methodC()是一组但methodA()依然会先于methodB()执行。这是Java和C/C不一样的地方之一C里函数参数的求值顺序在不同编译器下是未定义的Java则明确规定从左到右这也让代码行为更好预测。但有两个例外也就是传说中的短路运算符和||if (list ! null list.size() 0) { // ... }如果list是nulllist ! null为false短路生效右侧的list.size()根本不会被调用也就不会抛NullPointerException。这个特性如果你不理解可能觉得“为什么有时候if里面代码没执行就跳过了”如果你理解就知道这是Java故意的设计也是防空的惯用招数。但短路也能变成坑。比如boolean result (a 3) (b 5);如果第一个条件已经为false第二个b不会执行b的值就不会变。这在调试时很容易让人摸不着头脑。所以写含副作用的短路表达式时务必搞清楚“右侧不执行”的可能性。3.4 有了优先级表为什么我仍然劝你多写括号这一个建议我真心觉得价值超过前面所有知识点在复杂的表达式里用括号显式表达你的意图哪怕某些括号是多余的。原因有三个节省你的认知负担。读代码的时候你每次都要去回忆“这个运算符优先级高不高”时间久了人会累就会出错。规避不同语言之间的差异。你可能会从Java切到C#、Go、PHP它们的优先级表有细微差异依赖记忆容易踩坑。代码是协作产品。你写的表达式同事也要维护。能10秒看懂的表达式就不要让他花3分钟去查优先级。而且很多静态检查工具对复杂表达式会直接给出警告要求加括号。不要等到公司CI挂了再补现在就养成习惯。4. 算术运算符与赋值运算符最常用也最容易忽略细节4.1 整数除法、取余和溢出三个高频兄弟算术运算符很简单但总有三个地方埋伏着让人摸不着头脑的行为。第一个是整数除法int result 7 / 2; // 结果是3Java里整数之间做除法结果还是整数小数点部分直接丢掉不是四舍五入就是截断。如果你想要浮点数结果至少一个操作数要换成浮点类型double result 7 / 2.0; // 3.5很多初学者在写平均值、比例、百分比时栽在这里。比如计算一个数组的平均分写成sum / count得到的永远是整数你需要(double) sum / count或者sum / (double) count。第二个是取余运算符%。取余运算大多数情况下很简单17 % 5 得 2。但有个坑如果操作数里有负数呢答案是Java里%的结果符号和被除数左操作数保持一致-17 % 5 -2 17 % -5 2这个规则可以理解为先用绝对值的思路算出余数再把被除数的符号附上去。不要指望它和数学里的“模”一样永远是正数。第三个是溢出。int类型的最大值是21亿多两个int相乘很容易超过这个范围int a 1_000_000; int b 2_000_000; long c a * b; // 先按int相乘已经溢出了再赋给long也救不回来正确的写法是先让一个操作数转成longlong c (long) a * b;。这个问题在计算金额、文件大小、时间戳毫秒数时特别常见一定要养成“运算前评估可能的最大值”的习惯。4.2和--的前后缀区别不只是执行顺序i先用后加是很多初学者第一个接触到的“看起来有陷阱”的语法。实际上它的本质是前缀版本i先自增再返回自增后的值。后缀版本i先返回原值再执行自增。看起来很简单但到了复杂表达式里就考验人了。来个经典面试题int i 0; i i; System.out.println(i); // 输出多少答案是0。这个题很多工作两年的人也答不对。原因是右边i是先取i的当前值0作为表达式的值然后i自增变成1最后赋值又把0赋回给i所以最后是0。这个细节用一句话记自增发生在赋值之前还是之后取决于你在同一表达式里的位置。我的实际建议是尽量不要在复杂表达式里使用或--尤其是赋值表达式里。i单独成行没问题但在array[i] value这种写法里虽然能正常工作但可读性一般出错时也不好排查。代码风格越直白越安全。4.3 复合赋值运算符里藏着的强制类型转换、-、*这类复合赋值运算符写起来省事但很多人的认知空白在于复合赋值运算符自带一次强制类型转换。看这个例子short s 10; s s 1; // 编译报错int无法赋值给short s 1; // 编译通过神奇不神奇原因是s 1的结果是int直接赋给short会报错而s 1背后的等价写法是s (short)(s 1)有一个隐藏的类型转换。这在实际项目里有个隐患如果你用int类型的变量加来加去然后赋值给一个范围更小的类型复合赋值运算符会静默截断可能丢精度。所以不要以为和就是简写的关系它们在类型语义上有细微差别。4.4 浮点数运算为什么会得到0.30000000000000004部分开发者在写金融计算时踩过浮点精度的坑。二进制浮点数无法精确表示所有十进制小数比如double result 0.1 0.2; System.out.println(result); // 0.30000000000000004这不是Java的问题IEEE 754标准下的C、JavaScript、Python都一样。如果你要精确表示金额直接用BigDecimal构造参数传字符串而不是double比如new BigDecimal(19.9)千万别写new BigDecimal(19.9)那样精度损失在构造时就发生了。5. 关系运算符与逻辑运算符条件判断里的短路与类型之谜5.1比较基本类型和引用类型两套游戏规则关系运算符里最坑的永远是。它用在基本类型上比较的是值用在引用类型上比较的是地址是否相同。意思是两个不同对象即使内容完全一样也返回false。典型场景就是StringString a hello; String b hello; System.out.println(a b); // true但它俩指向常量池中的同一个对象 String c new String(hello); String d new String(hello); System.out.println(c d); // false两个不同对象很多初学者不理解为什么第一个是true。关键在于字符串常量的驻留机制。你写String a hello时如果常量池里已经有这个字符串就直接复用。这是JVM的优化不是的语义。实际开发中判断字符串相等永远用equals或者更安全的Objects.equals(a, b)前者可以避免a为null时报空指针。再聊一个面试高频题Integer缓存Integer x 127; Integer y 127; System.out.println(x y); // true Integer m 128; Integer n 128; System.out.println(m n); // false这是因为Integer在-128到127之间有一个缓存池自动装箱时直接复用缓存的对象超出范围就每次都new新对象。结论很简单包装类型比较数值用equals或者拆箱成基本类型再比较。5.2和||的短路以及一个不太聊的和|逻辑运算符里和||是短路版本和|是非短路版本。这在按位运算里也用到但在逻辑判断场景里if (a 0 b 5) { // ... }如果a 0是falseb仍然会被执行因为不会短路。你本意可能只是想判断两个条件却无意中多了一次副作用。大部分人不会在日常代码里这么写但如果你在做位掩码判断时使用了而不是一定要清楚它俩行为不同。还有一个逻辑运算符的宝藏技巧用逻辑表达式直接赋值替代繁琐的if-else。比如boolean isValid name ! null name.length() 3;这种写法既清晰又安全。但再往前一步用三元表达式判断并赋值String status user.isActive() ? 正常 : 禁用;这就是很典型的优雅写法可读性也不错。但记住我前面说的不要嵌套太深。5.3instanceof类型检查的优雅姿势与注意点instanceof运算符用来判断一个对象是否是某个类的实例或其子类的实例if (obj instanceof String str) { System.out.println(str.length()); }Java 16开始支持这种“模式匹配”写法不用先判断再强转省了一行代码。在重写equals方法时这是标准套路public boolean equals(Object o) { if (this o) return true; if (!(o instanceof User user)) return false; return userId user.userId; }注意一个细节JDK 14之前instanceof右侧必须是一个类型名不能是变量JDK 16之后模式匹配就很好用了。另外如果用instanceof判断null结果永远是false所以不需要额外的null判断。6. 位运算符和移位运算符被低估的编码利器掌握后代码性能与优雅度双提升6.1 按位与、或、异或、取反权限系统的底层实现位运算在日常业务代码里出场率不高但真到用的时候基本都是核心模块权限、开关、状态机、压缩。先说最常用的按位操作按位与两个位都是1才为1常用于掩码操作。|按位或任一个位为1即为1常用于开启标志。^按位异或两个位不同才为1常用于切换标志。同一值异或两次能恢复原值这个特性在简易加密和交换变量时很有用。~按位取反每位取反负数在Java中是通过补码表示的所以~5等于-6这个初看很反直觉但记住公式~x -x - 1就可以。经典的权限控制模式如下// 权限常量用不同二进制位表示 public static final int READ 1 0; // 0001 public static final int WRITE 1 1; // 0010 public static final int EXECUTE 1 2; // 0100 // 用一个int存所有权限 int permission 0; permission | READ; // 开启读权限 permission | WRITE; // 开启写权限 boolean canWrite (permission WRITE) ! 0; // 判断是否有写权限 permission ~WRITE; // 关闭写权限这种写法的优势是用一个int就能搞定一组开关状态数据库存一个字段就行查询时直接用SQL位运算筛选性能很好。6.2 移位运算符、和三兄弟的语义差异Java提供三种移位运算符左移低位补0相当于乘2的n次方前提是不溢出。右移带符号右移左边补符号位。正数补0负数补1结果接近除以2的n次方并向下取整。无符号右移无论正负左边一律补0。这个在Java里独有C和C没有。看个例子int x -8; int y x 1; // -4符号位补1 int z x 1; // 2147483644最高位变成0无符号右移在处理无符号数值、哈希运算、颜色分量提取时非常有用。比如从一个int里取出RGB各通道值就靠移位加掩码int color 0x66CCFF; int red (color 16) 0xFF; int green (color 8) 0xFF; int blue color 0xFF;这个套路在图像处理、前端颜色转换、游戏开发里很常见。6.3 位运算的技巧奇偶判断、交换变量、2的幂检测面试题里常有位运算技巧实际生产中偶尔也有奇效奇偶判断(n 1) 0为偶数否则为奇数。比取模更快一些。交换两个变量不用第三个变量a ^ b; b ^ a; a ^ b;这个技巧看起来很酷但强调一次实际开发中不要用这种写法炫技可读性差编译器也未必比你聪明多少。了解原理即可。判断一个整数是不是2的幂boolean isPowerOfTwo (n 0) ((n (n - 1)) 0);因为这个逻辑本质上是一个很漂亮的数学性质2的幂次方的二进制表示只有一个1减1之后高位全部翻转与操作后必为0。6.4 为什么位运算在哈希和状态压缩中不可替代HashMap的扩容和数组索引定位处处都有位运算的影子hash ^ (hash 16)、(n - 1) hash。如果你去读一下JDK源码会发现位运算在追求极致性能的地方无处不在。状态压缩也是像摆棋类游戏、八皇后问题用一个int的各位表示一行棋格的状态判断冲突只需一次与运算。理解位运算不是让你业务代码里到处炫技而是让你读源码、处理底层性能问题时能跟上作者的思路。7. 三元运算符和类型转换优雅与陷阱并存的两兄弟7.1 不要用三元运算符做复杂嵌套但必要的场景非常顺手三元运算符条件 ? 值A : 值B是Java里唯一的三目运算符。最典型的使用场景就是简单条件赋值我前面已经给过一个例子。它比if-else更紧凑但有两个注意点嵌套三元可读性极差。a 0 ? 1 : b 0 ? 2 : 3已经不容易看了再往上叠基本是灾难。三元运算符的两个结果分支会触发类型统一。比如int x flag ? 1 : 2.0;结果是2.0对应的int强转可能丢精度编译器还会警告。更经典的坑是Object result flag ? 1 : 字符串;1会被自动装箱成Integer然后两个分支统一类型时可能提升为Object这个过程如果你不理解调试时只能看到result的类型不太对但不知道机制。简单说三元运算符的两个分支类型必须能够统一如果类型差异大别硬塞进同一个表达式拆成if-else更清晰。7.2 赋值运算符里的隐式类型转换int到short、char到intJava是强类型语言不同类型之间的赋值和运算有一套自动类型转换规则自动转换小范围类型可以自动转到大范围类型。byte - short - int - long - float - double以及char - int。为什么float排在long后面因为float虽然精度不总是足够但取值范围比long大转换规则按范围走。强制转换大范围转到小范围需要显式(type)。比如int转byte如果数值超出范围高位截断结果就不可预期。举一个实际开发中容易翻车的例子char c A; int code c; // 自动转成65没问题 char lower (char) (code 32); // 转成a但必须强转还有数值计算中的类型提升byte a 10; byte b 20; byte c (byte) (a b); // a b 结果已经是int必须强转这个规则很多新手不理解为什么两个byte相加就会编译报错。原因是Java语言规范规定对于byte、short、char之间的算术运算结果一律提升为int。这是为了减少实际生产中8位、16位计算的溢出问题宁可提升计算再截断也不让中间过程丢精度。7.3 字符串拼接运算符到底算算术还是拼接Java里被重载了两层含义数值相加和字符串拼接。当两侧出现String时它就把其他操作数转成字符串拼接起来。这个行为本身不难但有一个顺序问题System.out.println(1 2 3 4); // 输出334而不是37因为表达式从左到右求值先算1 2得3再和字符串拼成3后面3 4因为左侧已经是字符串了就只能拼接字符串334。如果你希望输出37需要加括号1 2 (3 4)。涉及大量字符串拼接的时候还要考虑性能。在循环里用拼接字符串会产生大量中间String对象长期运行的内存压力不小。正确做法是用StringBuilderStringBuilder sb new StringBuilder(); for (String item : list) { sb.append(item); }Java编译器在某些简单场景会自动把优化成StringBuilder但循环体内的拼接不一定总能优化到位养成显式使用StringBuilder的习惯更稳妥。8. 运算符优先级总览与“括号优先”的实战守则8.1 一张表读懂Java核心运算符优先级为了照顾用表格学习的人我整理一个简化版优先级表按从高到低排列优先级运算符说明最高() [] .括号、数组下标、成员访问高 -- ~ ! (type)后缀自增、前缀自增、取反、转型中高* / %乘除取余中 -加减字符串拼接也算中低 移位低 instanceof关系比较较低 !相等判断更低按位与低^按位异或较低|按位或很低逻辑与最低||逻辑或右结合? :三元右结合 - * / % ^注意几个反直觉的点instanceof和关系运算符同一档比高比^高^比|高。这意味着a b c会先算b c所以我之前在(flags 0xFF) 0xFF那个例子里反复强调加括号不是小题大做。8.2 真实的表达式求值顺序案例从一行代码里读出全部规则来个综合案例把所有规则串一遍int a 1; int b 2; int c 3; boolean flag false; int result flag ? a : b-- c;分析这段代码三元的条件flag先求值false所以走b-- c分支。b--是先取b当前值2再自减成1但表达式的值是2。2 3得5赋给result。最终a还是1b变成1c是3result是5。如果你一开始没算对问题多半出在b--上。再来看一个更多运算符的版本int x 2; double y x/2 x * 1.5;逐步拆x取2x变32/2在整数除法里等于1。此时x已经是3所以3 * 1.5得4.5。1 4.5 5.5。关键点在于同一个表达式里x经过了自增后的值和原始值混在一起很容易让人错算成1 3.0 4.0实际上x / 2里的x用的是自增前的2。所以这种代码我强烈不建议在生产环境里出现因为可读性差、易出错价值也高不了多少。8.3 为什么说“不要用运算符玩小聪明”有一句话我想写在所有篇幅的最后也是我带团队时最常说的一句话代码的首要读者是维护它的同事而不是编译器。运算符和表达式是Java的底层基础掌握它的原理和改进不了代码质量的话就该站在“可读性”的高度做出取舍能加括号就加括号哪怕多写两个字符。不要为了炫技写a ^ b; b ^ a; a ^ b;交换变量。不要在复杂表达式里混用和多个算术运算。判断相等两件事分开基本类型用对象用equals。浮点数比较大小不要直接比较相等除非你知道自己在做什么。9. 常见问题对照速查表与面试高频题实录9.1 日常开发中高频问题的排查速查表问题现象可能原因解决方案整数相除结果少了一位小数整数除法直接截断至少一个操作数转成doublefloat/double计算出现小数误差IEEE 754精度限制精确计算用BigDecimal构造参数传字符串两个字符串内容一样但为false比较的是引用地址改用equals或Objects.equals两个超过127的Integer用不相等Integer缓存池范围是-128到127包装类型比较用equalsif (a b c)结果不对优先级高于加括号写成(a b) c循环里大量字符串拼接很慢产生大量中间String对象改用StringBuilder三元表达式里两个分支类型差异大自动类型提升导致结果类型出乎意料拆成if-else或显式强转复合赋值运算符丢了精度自带强制类型转换明确评估范围必要时先强转再运算取余结果带负数Java符号跟随被除数需要正余数时手动调整((a % b) b) % b9.2 面试官最爱考的几个表达式求值题除了前面提到的int i 0; i i;再补充几个典型的int y 10; int z y-- - --y;这个题建议你自己算一遍再运行验证这里不给答案算完就会对前后缀自增有更深理解。int[] arr {1,2,3}; int i 1; arr[i] arr[i] 10;问执行后数组是什么关键是确定arr[i]里i用的是哪个值。boolean a false; boolean b true; boolean c b || (a false);问c是多少这个考短路还有优先级优先算然后||短路其实b是true时直接走完了。switch表达式里能不能用case 1 2答案是可以条件是常量表达式才行。Java要求case值必须是编译期常量1 2满足但普通变量 2不满足。final int x 5; int y x 3;这个没问题因为final修饰的常量在编译期就可确定。这些题的价值不在于“考倒你”而是逼着你把“表达式求值顺序”这层逻辑想清楚。死记答案没意义拿着IDE跑一遍再对着我们前面讲的规则做推导收获大得多。9.3 几个我亲历的项目事故都是运算符惹的祸说三个我真实遇到过的线上事故帮助你理解这个知识点到底有多重要。第一个是金额计算。同事用一个int保存以“分”为单位的金额两个金额相加超过int上限溢出后变成负数导致对账失败。排查很久才发现是溢出。从那以后凡是金额相关字段一律用long保存分或者直接用BigDecimal。第二个是Integer比较。同事在缓存里拿到两个对象用判断是否等于某个常量结果小值时正常大值时偶发异常。查了半天才发现因为Integer缓存池的问题。从那以后团队要求包装类型相等判断一律用Objects.equals。第三个是短路导致的漏更新。一个日志统计功能里代码写着count 0 count 0因为逻辑写得太隐晦导致在某些条件下计数不更新。没人注意到这个细节。最后把这种隐晦逻辑全部改成独立判断加自增问题才消失。这些事故都不是多高深的技术恰恰是因为基础运算符的细节没掌握才在复杂的业务场景里爆雷。基础不牢后面真是每天都得给代码还债。10. 实操总结把运算符与表达式落到日常编码里的5个习惯写到这里其实光讨论理论已经到头了我更想送你几句能直接用起来的习惯复杂表达式优先加括号不要考验同事的优先级记忆能力。类型转换能显式就显式不要依赖隐式转换尤其是在有窄化风险时。判断相等分两种基本类型看值引用类型看内容别混用。复合赋值运算符要警惕隐式转型赋值前先想类型的最大范围。前后缀自增别塞进复杂表达式单独写一行读起来不累逻辑也不容易错。保持这几个习惯之后你会发现代码里与运算符相关的bug会明显变少。不是运算符本身把你坑了而是你以为自己懂了结果在某个细节上判断失误。如果你正处在学习Java的阶段这篇文章里的代码建议你全部手敲一遍一个都不要复制粘贴。手敲代码这个动作看着笨拙但调错的过程会逼着你把每个表达式求值的细节都过一遍脑子效果比读十篇文章都好。等你哪天能不看资料自己推导出i i的输出是0并且能解释清楚每个步骤这个知识点基本就彻底是你的了。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑