
搞了这么多年编程我见过太多人在操作符上翻车。别小看这个基础中的基础去年我带的一个实习生从C转Java写了个if (a b)直接编译不过一脸懵地跑来问我Java凭什么不让这么写。反过来我另一个同事Java出身去写嵌入式C一句printf(%d, i i)把老C工程师都看笑了。操作符这东西表面上看不就是 - * /那点事吗真逐条对比下来Java和C在操作符上的差异比你想象的大得多背后藏着两种语言完全不同的设计哲学。这篇文章把两者的核心区别、高频坑点、面试题全部过了一遍基于我平时写代码和带新人的实际经验不整虚的直接上干货。无论你是准备Java面试、在啃C语言基础还是打算从一门语言切到另一门这篇都值得你花十分钟认真看完。1. 为什么说操作符最能看出C和Java的性格1.1 C语言把机器的能力直接交给你C语言当年是为了写操作系统和底层驱动而设计的所以操作符体系几乎是照着CPU指令集长的。位运算、移位、自增自减、复合赋值、逗号运算符在C里都是一个运算符对应几条机器指令写起来非常顺手。比如a b c 0这种连续赋值在C里一气呵成因为赋值表达式本身是有值的最终整个表达式的值就是0机器层面不过是一串寄存器操作。这种设计给了程序员极大的表达自由但代价是编译器几乎不帮你判断这句代码是不是你脑子里想的那句。最典型的就是if (a 10)在C语言里这是完全合法的代码先把10赋给a再判断a是否为非0结果是真进入分支。如果你本意是if (a 10)这个bug编译器不会报错最多给个warning很多旧编译器连warning都不给。我带过的新人里至少三个人在这种地方花过半天时间调bug。另一个直观表现是C语言操作符数量多、优先级表密密麻麻、、、? :这些运算符的优先级都反直觉稍不留神写出来的语义就完全不是你想的那样。C语言默认程序员是专业的所以把所有的自由度都交出来出问题是你自己的事。1.2 Java用编译器和规范帮你兜底Java诞生于上世纪90年代面向的是应用层开发和跨平台需求设计哲学非常明确安全、可移植、让程序员少犯错。在操作符这件事上Java做的是收窄。一方面保留了C的大部分运算符降低C程序员的迁移成本另一方面在语言规范层面堵死了C里最容易踩的坑。条件判断必须是boolean类型if (a b)直接编译报错数组访问自动做边界检查整数运算的位宽在规范里写得清清楚楚。Java还补了两个C没有的东西无符号右移专门解决Java没有无符号整数类型的问题instanceof类型判断运算符用来做运行时类型检查。更重要的是Java对运算结果有一套完整规范几乎没有未定义行为这种概念。同样的表达式在C里换个编译器结果可能就变了在Java里结果是固定的、可预期的。这两种风格没有绝对的高下之分C适合贴近硬件的场景Java适合追求工程确定性的场景。你只需要记住操作符这块Java的规则比C话多但管得宽C的语言规范比Java话少但坑深。1.3 一张表看清整体差异对比维度C语言Java布尔类型C99起有_Bool平时习惯用int的0/非0代替原生boolean条件必须是booleanif (a b)合法先赋值再判断经典坑编译报错无符号右移没有有逗号运算符支持表达式任意位置可用不支持for循环语法除外sizeof运算符没有数组有length属性instanceof没有有字符串比较用strcmp比较的是地址用equals()比较的是引用地址有符号数溢出有符号溢出是未定义行为规定了按补码回绕数组边界检查不检查越界就是野指针运行时自动检查直接抛异常这张表基本概括了两边操作符体系的核心差距。下面把最容易出事的几组操作符逐个拆开讲。2. 六个必看核心区别逐个拆开讲2.1 和 一门语言堵住了入门最大的坑这一组是两门语言新手差异最大的地方。在C语言里int a 5; if (a 10) { // 一定会执行而且a变成了10 }这段代码在C里是合法且可运行的先把10赋给a再用a的值10作为if的条件非0为真于是进入分支。如果你的本意是判断a是否等于10这代码碰巧也能走进分支所以表面上看起来对。但一旦赋的值是0int a 5; if (a 0) { // 赋值后a0条件为假分支不会执行 }bug就这样安静地出现了分支不执行a也被清零了。这就是C语言经典到不能再经典的笔试题与线上事故来源。Java把这条坑直接堵死了int a 5; // if (a 10) {} // 编译错误不兼容的类型: int无法转换为boolean因为Java规定if、while、for的条件必须是boolean类型而赋值表达式的值是int类型对不上编译器直接拒绝。很多C转Java的人刚来时很不适应觉得凭什么不让我这么写其实这是语言在设计层面对你的一种保护。但Java也不是完全没有坑。如果赋值的是一个boolean变量boolean flag false; if (flag true) { // 编译通过因为 flag true 的值是true属于boolean类型 System.out.println(会执行); }这种情况编译器就拦不住了。我的实际建议是不管写C还是写Java都别把赋值当作条件用真需要的时候至少加个注释免得坑到下一个接手代码的人。2.2 自增自减与未定义行为C的自由是双刃剑i和i的区别两门语言基本一致前者先用后加后者先加后用。int i 1; int a i; // a 1, i 2 int b i; // i 3, b 3Java里结果一模一样。真正的区别在于一个表达式里对同一个变量进行多次修改时C语言会进入未定义行为的雷区。最典型的int i 1; int r i i; // 未定义行为结果不可预测为什么不可预测因为C标准允许编译器自行安排对i的读取和写入顺序。GCC可能算成4Clang可能算成5换一个优化级别结果又不一样。这类代码在C语言笔试题里高频出现正确的回答不是给出一个数字而是明确指出这是未定义行为任何结果都不能作为标准答案。Java这边不一样。Java语言规范明确规定了表达式求值顺序是从左到右i i的结果是确定的int i 1; int r i i; // 先算左操作数 i值为1i变成2 // 再算右操作数 ii先自增成3值为3 // 最后相加r 1 3 4结果是确定的但我依然不推荐任何人写这种代码。写代码是给三个月后的自己看的不是为了炫技考编译器。补充一个Java特有的小陷阱i i;的结果。很多人以为是2实际是1int i 1; i i; // i 最后还是 1不是2原因是Java的求值顺序先取i的值1再把i自增为2最后把拿到的值1写回i所以i被打回原形。这道题在Java面试八股文里出现率不低考察的是对取值、自增、赋值三步顺序的理解。2.3 和 短路与非短路的差别在Java里更明显和||是短路运算符左边能决定结果时右边不再计算。和|则老老实实把两边都算完。这个规则两门语言一致。但两门语言对的用法差异很大。C语言没有真正意义上的bool类型可以随意用在整数上做位运算用在逻辑判断上。由于0/非0的语义松散和用混的情况很常见编译器也不会拦你。Java里boolean是独立类型、||只接受boolean操作数、|既可以对整数做位运算也可以对boolean做非短路逻辑运算。这里面有个很多Java新手不知道的细节用在boolean上时是非短路与。看这个经典例子String s null; // if (s ! null s.length() 0) { // 上面这行会抛NullPointerException因为 两边都会执行 // } if (s ! null s.length() 0) { // 安全左边为false时右边不执行 }这个知识点别看简单实际开发里很多人图省事或者手快写成了单个线上出NPE的不在少数。判断一个Java开发者功底扎不扎实问一句和在布尔表达式里的区别基本能筛掉一批人——很多人只知道可以作为位运算不知道boolean上也分短路与非短路。C语言里还有一个反直觉的用法如果你在逻辑判断里写if (a b)编译器会按位运算处理判断的是a和b按位与的结果是否为0而不是a且b是否为真。C语言里没有类型系统替你分辨位操作和逻辑操作你得自己在脑子里分清。2.4 与移位运算Java独一份的无符号右移移位运算符和两门语言都有含义基本一致左移低位补0右移分两种情况有符号数的是算术右移高位补符号位无符号数的是逻辑右移高位补0。关键差异Java多了无符号右移不论操作数正负高位一律补0。C语言没有这个运算符。为什么Java要单独搞一个因为Java里几乎所有基本整数类型都是有符号的byte、short、int、long只有char是无符号16位。做位运算时经常想把数据当作纯比特串处理不希望负数的符号位被继承下来。C语言程序员可以用unsigned int绕过去Java没有无符号int可用于是专门设计了一个运算符。看个例子int a -1; System.out.println(a 1); // -1算术右移符号位仍然是1结果还是-1 System.out.println(a 1); // 2147483647无符号右移最高位补0变成2^31-1-1 1等于2147483647这道题我见过至少五次出现在Java面试题里属于送分题但真能在场上快速答出来的不多。另一个Java和C的移位差异在移位距离上。C标准规定移位距离超过操作数位宽是未定义行为。比如32位int写1 32真正的CPU指令可能帮你按32取模但编译器优化时可能直接生成你意想不到的代码结果完全不可信。Java则明确规定int类型的移位距离按32取模long按64取模。int a 1; System.out.println(a 32); // 等价于 a 0结果是1 System.out.println(a 33); // 等价于 a 1结果是2顺带说一个优先级坑加法的优先级高于移位所以x 2 1是x (21)不是(x 2) 1。C和Java都这样记住了能少踩一个坑。2.5 比较操作符String和对象比较的经典误区、、、、、!在C语言里都是对数值或指针的地址做比较语义直接。Java里基本类型比较也一样但在引用类型上比较的是引用是否指向同一个对象而不是内容是否相等。这是从C到Java必踩的第一个大坑字符串比较。C语言的字符串本质是字符数组/字符指针用比较两个字符串比较的是首地址而不是内容必须用strcmpchar *s1 hello; char *s2 hello; if (s1 s2) { // 进不进这个分支取决于编译器是否把两个字面量合并到同一块内存结果不保证 } if (strcmp(s1, s2) 0) { // 这才是比较内容 }Java里字符串是对象比较引用地址内容比较必须用equals()String a new String(hello); String b new String(hello); System.out.println(a b); // false两个对象地址不同 System.out.println(a.equals(b)); // true内容相同 String c hello; String d hello; System.out.println(c d); // true字面量在常量池复用同一个对象最后一行是Java新人最困惑的地方为什么同样是有时候true有时候false。原因是Java字符串字面量会在常量池中复用c和d指向同一个对象而new String每次都在堆里新建对象。这属于Java面试八股文里出现频率最高的几个点之一。比较操作符还有一个Java特有的instanceof用来判断对象是否为某个类型或其子类型的实例Object obj hello; if (obj instanceof String) { String s (String) obj; System.out.println(s.length()); } // Java 16开始支持模式匹配 if (obj instanceof String s) { System.out.println(s.length()); }C语言没有instanceof因为C的类型系统在编译期就定死了没有运行时类型识别。这也是两门语言设计哲学差别的缩影C靠编译期解决大部分问题Java在运行期留了很多后门。2.6 instanceof、sizeof、逗号类型与表达式操作符的增减上面讲了instanceof是Java独有的。反过来C语言里也有Java没有的操作符或用法。sizeof是C程序员的老朋友用来求类型或变量占用内存的字节数。它是编译期运算符不是一个函数int arr[] {1, 2, 3, 4, 5}; int n sizeof(arr) / sizeof(arr[0]); // 经典求数组长度写法结果是5Java里没有sizeof你也不需要它——规范固定了基本类型的字节宽度int永远是32位long永远是64位跨平台一致。想求数组长度直接用arr.length属性注意这是字段不是方法后面不加括号。Java的String长度则是str.length()方法一个字段一个方法也是容易记混的点。逗号运算符是C语言独有的表达式运算符int a; a (1, 2, 3); // 逗号表达式从左到右求值结果取最后一个a 3 for (int i 0, j 10; i j; i, j--) { // C里 for 循环的多个变量控制很自然 }C的逗号运算符能在任意表达式位置使用不只是for循环。Java没有逗号运算符int a (1, 2, 3);直接编译报错。Java的for循环虽然也支持多个初始化变量和多个更新语句for (int i 0, j 10; i j; i, j--) { // 这是Java的for语法特性不是逗号运算符 }但要搞清楚这属于Java for语句的语法糖逗号在这里只是分隔符并不是把逗号作为运算符暴露给其他表达式场景。互转时这个差异很容易踩在Java里想写类似C的逗号表达式只能拆成多行或者抽成方法。3. 类型转换、溢出和优先级细节决定生死3.1 隐式类型提升byte和short的隐形变身两门语言在做算术运算时都有隐式类型提升但规则和后果不太一样。C语言的整型提升规则char、short参与运算时先提升为int如果int不够容纳比如某些平台short和int一样长就提升为unsigned int。同时有符号和无符号混用时的规则很绕稍不注意就有符号性bug。Java的规则更固定byte、short、char参与运算一律提升为int赋值回去时必须显式强转byte a 1; byte b 2; // byte c a b; // 编译错误不兼容的类型: 从int转换到byte可能会有损失 byte c (byte) (a b); // 必须强转这个坑在操作byte数组、做编解码、处理二进制协议时特别常见。写半天编译器一个可能损失精度的红叉直接把你拦住。Java之所以这么设计是为了避免C语言那种在8位机上int和short一样长的可移植性混乱——Java里int永远是32位规则越固定跨平台行为越一致。还有一个Java特有的坑char是16位无符号整数byte是8位有符号整数。很多人以为char就是字符其实它本质上是一个无符号16位整数可以直接参与算术运算char ch 65; ch 1; // ch变成66对应字符 BC语言的char尤其要小心signednesschar到底是有符号还是无符号由编译器和平台决定标准没有强制规定。同样的位运算代码在ARM和x86上可能结果不一样所以写底层的人一般会用unsigned char或int8_t/uint8_t明确指定位宽与符号。3.2 整型溢出C是未定义Java是规定好的回绕这是两门语言最气质不同的细节之一。C语言里有符号整数溢出是未定义行为。编译器会假设你的代码不会溢出并基于这个假设做优化。比如int a INT_MAX; int b a 1; // 未定义行为在GCC开-O2优化后这段代码可能直接进一个你完全没想到的分支因为编译器根据不会溢出推导出结论并删掉了某些判断。你以为是溢出回绕变成INT_MIN但在未定义行为的加持下什么都可能发生。unsigned int溢出倒是明确规定了回绕但signed就真别赌。Java规定死了所有整数溢出都按二进制补码回绕。int a Integer.MAX_VALUE; // 2147483647 int b a 1; // 结果是 -2147483648稳定可预期Integer.MAX_VALUE 1 Integer.MIN_VALUE在Java里是永远成立的事实笔试里也喜欢出。但注意可预期不等于没毛病业务代码里对金额做int运算溢出一样会出问题。想要主动捕获溢出可以自己写位运算判断但工程上我更推荐直接使用Math.addExact(a, b)溢出时它直接抛ArithmeticException省心得多。3.3 三目运算符的类型推断陷阱三目运算符cond ? a : b在C里很常用类型平衡规则相对简单两个操作数是数值类型时按隐式转换规则平衡成一个公共类型比如int和double混用结果会变成double。Java的三目运算符更复杂因为涉及引用类型和自动拆装箱。这里藏着一个经典面试题三目运算符的NPE。boolean flag true; Integer value null; Integer result flag ? value : 0; // 当 flag 为 true 时这一行会抛NullPointerException为什么因为Java推导三目表达式类型时看到左边是Integer可以拆成int右边是int于是把整个表达式的类型定为int。执行到value分支时必须把value从Integer拆箱成intvalue是null拆箱就是NPE。很多人不理解明明result是Integer直接装下value不就行了吗但类型推断不是按目标类型倒推而是先独立确定表达式类型再做赋值转换。这个坑在Java 8之前就有到现在还是不停地坑人。解决办法很简单不要混用包装类型和基本类型Integer result flag ? value : Integer.valueOf(0); // 两边都是Integer不拆箱3.4 优先级对照表与三个经典优先级坑C和Java的运算符优先级整体上是一脉相承的因为Java继承了C的大部分语法骨架。从高到低的核心顺序大致是优先级高→低C语言Java1() [] . -后缀 --() [] .后缀 --2前缀 --一元 - ! ~ * (类型) sizeof前缀 --一元 - ! ~new(类型)3* / %* / %4 - -含String连接5 6 instanceof7 ! !89^^10||1112||||13? :? :14 - ... - ...15,无注意这张表做了简化真正完整版比这细得多。我不推荐任何人死记完整优先级表日常写代码多套括号比什么都强。三个经典优先级坑C和Java都一样加法的优先级高于移位所以x 2 1等于x (21)不是(x 2) 1。相等判断的优先级高于位与所以x 0xff 0会被解析成x (0xff 0)也就是x 0恒为0。正确写法是(x 0xff) 0。赋值运算符的优先级非常低只比逗号运算符高一点点。所以while (c getchar() ! EOF)会被解析成while (c (getchar() ! EOF))先做比较再把结果0或1赋给c。这个坑让无数C初学者在读取字符时栽过跟头也是经典的C笔试优先级题。4. 面试笔试高频题实战拆解4.1 Java面试八股高频操作符题整理几个Java面试题里出现频率极高的操作符题每道都有明确的考察点。第一题int i 1; i i; 最终i是多少答案是1。流程拆三步先取i的值为1再把i自增为2最后把拿到的值1写回i。答错的人往往把i直接理解成整体等于i自增之后的值。第二题int a -1; a 1 是多少答案是2147483647即2^31 - 1。是无符号右移高位补0不管正数负数都按位串处理。这题考察对无符号右移的理解顺带提醒你有符号右移对-1会一直是-1因为符号位是1右移补的也是1。第三题Integer a 100; Integer b 100; a b 是否为true答案是true。因为自动装箱时Integer.valueOf对 -128 到 127 范围内的值做了缓存返回同一个对象。但如果上下界换成128Integer a 128; Integer b 128; System.out.println(a b); // false这题考察自动装箱缓存机制。老实说生产代码里根本不该用比较两个Integer应该用a.equals(b)或者a.intValue() b.intValue()。第四题为什么推荐用异或而不是临时变量交换两个intint a 3, b 5; a a ^ b; b a ^ b; a a ^ b; // a 5, b 3原理是异或的性质a ^ a 0a ^ 0 a异或满足交换律和结合律。拆开算第一步后a 3^5第二步b (3^5)^5 3第三步a (3^5)^3 5。看起来省了一个变量但实际工程里我几乎不用这种方式可读性差而且后面会说它在数组场景有坑。面试里能推导原理才是重点不是让你在生产里真这么写。第五题a b和new String(ab)有什么区别a b在编译期会做常量折叠直接变成常量池里的ab如果是动态拼接s t底层会创建StringBuilder调用append再toString。这题考查String拼接的底层严格说不算传统意义上的运算符但是Java里唯一支持重载语义的操作符只对String和基本类型/包装类型生效值得单独记一笔。4.2 C语言笔试高频操作符题C语言的操作符题往往更狠很多直接就是未定义行为题。我的建议是见到同一个变量在同一个表达式里被多次修改第一反应就是未定义不要试图分析出一个确定答案。典型题1int a 1; printf(%d %d, a, a);输出是什么没有标准答案。C标准不规定函数参数的求值顺序有的编译器从左到右有的从右到左而且a在同一表达式里被多次修改属于未定义行为。这题的正确打开方式是明确说在C里这是未定义行为结果不可移植。能答出未定义这三个字比背一个数强多了。典型题2统计一个整数二进制表示中1的个数要求效率高。经典解法是x x (x - 1)这个操作每次能消掉x最低位的1int countOnes(int x) { int count 0; while (x) { x x (x - 1); count; } return count; }比如x 12二进制1100x-1 10111100 1011 1000一次消掉一个1循环结束count就是2。这个操作在C面试里属于必背级技巧因为C语言几乎不提供高级容器和标准函数位运算就是你的标准库之一。典型题3判断一个数是不是2的幂。本质是看二进制里有没有且仅有一个1用x (x - 1)消掉唯一一个1后应该变成0但还要排除0本身int isPowerOfTwo(int x) { return x 0 ((x (x - 1)) 0); }典型题4sizeof相关。int arr[10]; printf(%d\n, sizeof(arr)); // 一般是 40前提是int占4字节 printf(%d\n, sizeof(arr[0])); // 4 printf(%d\n, sizeof(arr) / sizeof(arr[0])); // 10数组长度但如果arr作为函数参数传入那sizeof(arr)就是指针的大小不再是数组大小。这是C面试高频点数组名在传参时退化成指针。4.3 同一种技巧在两种语言里的差异异或交换异或交换在C和Java里都能写语法一样但有一个两门语言共通的坑必须单独拿出来讲当交换的两个下标指向同一个数组元素时会把元素清零。int arr[] {1, 2, 3}; int i 0, j 0; arr[i] arr[i] ^ arr[j]; arr[j] arr[i] ^ arr[j]; arr[i] arr[i] ^ arr[j]; // arr[0] 变成了 0因为arr[0] ^ arr[0] 0第一步就把元素清成0后面怎么异或都是0。这个bug在快排、堆排这类需要交换元素的分治算法里特别隐蔽当i j触发自交换时就会出现。Java和C一个都没躲过。我的实际经验是除非明确知道两个下标不可能相等否则别用异或交换数组元素老老实实写临时变量最安全。面试炫技法可以工程里稳定和可读性优先。5. 语言切换时如何快速调整操作符思维5.1 C转Java最容易踩的五个坑我见过太多C功底不错的人一写Java就浑身别扭多数问题集中在操作符的使用习惯上。第一个坑条件里直接赋值。C的if (a b)在Java里是编译错误很多人第一反应是啊这都不会过然后不自觉地改成if (a b)。这其实是好事Java从语法层面逼你改掉C时期的坏习惯。第二个坑字符串比较。C用strcmpJava用equals()。但Java的字面量常量池导致偶尔返回true这个偶尔最要命——本地测试全过换个动态生成字符串的线上场景就全崩。我的建议是Java里所有字符串内容比较一律用equals或Objects.equals别赌。第三个坑sizeof依赖。C老手写代码时脑子里经常在估算结构体大小到了Java发现没有sizeof一开始会慌。其实Java的设计目标就是不让你关心内存布局数组长度arr.length集合大小list.size()够了。第四个坑数组边界。C里arr[i]越界是个静默炸弹可能悄无声息地踩坏别的变量。Java里越界直接抛ArrayIndexOutOfBoundsException运行期能看到异常栈。这个差异不算操作符本身但和[]运算符直接相关值得提一嘴别嫌Java啰嗦异常能帮你早点发现bug。第五个坑位运算结果赋值。Java里byte运算完是int直接赋值回byte会编译报错必须强转。C里写顺手了不觉得到了Java会被编译器反复打断。解决办法是养成显式强转的习惯同时理解为什么——Java在保证跨平台一致的整型宽度。5.2 Java转C必须补的四个概念反向切换Java程序员刚碰C时通常会在下面四个地方懵。第一个概念布尔是假的。C里没有真正的bool类型C99之后有_Bool但老代码大量用int任何非0值都是真0是假。if (-1)成立if (3.14)也成立。Java程序员写惯了严格的boolean会觉得C规则很随便但理解了这是向硬件靠拢的设计就好办了。第二个概念未定义行为是真实存在的。Java几乎规定了所有运算的最终结果C则把很多细节交给编译器和硬件。i i、INT_MAX 1、数组越界访问结果都可能无法预料。Java程序员一开始觉得C怎么这么不靠谱其实这是C在性能和可移植性之间做的取舍——信任程序员不强制检查。第三个概念char通常只有一个字节不是Unicode字符。Java的char是16位无符号能放下大部分Unicode字符。C的char一般只有8位存中文就废了得用wchar_t或字符数组配合编码。字符串处理的思维方式也要变C字符串是\0结尾的字符数组没有length属性得用strlen遍历这和String对象差别非常大。第四个概念指针与取地址。严格说指针不是运算符但*和作为运算符时取地址、解引用这些操作和Java的引用完全是两回事。Java程序员一开始不习惯int *p a;这种写法但理解了地址这个抽象之后就融会贯通了。Java的引用更安全但没有算术运算C的指针可以做p移动这是数组和指针配合的核心玩法。5.3 平时写代码我的一些预防习惯最后分享几个这些年沉淀下来的操作符预防习惯不分语言通用。第一优先级不确定就加括号。我见过太多人为了显得厉害不写括号结果三个月后自己都看不明白。加了括号可能有啰嗦的嫌疑但绝不会在优先级上翻车。代码是给人看的。第二写C语言时把常量放比较符左边。if (5 a)比if (a 5)稳得多因为手误写成if (5 a)时编译器必然报错而if (a 5)是合法代码。这是用规则设计对抗人类手指肌肉记忆的经典技巧。第三Java里条件表达式统一用、||不使用、|做布尔逻辑。单的非短路特性基本是百害无一利除非明确需要两侧都执行比如两侧都有必须执行的副作用否则一律短路。第四C语言做位运算前先确认类型有没有符号。要处理纯位串优先使用uint32_t、uint8_t这类明确位宽和符号的类型避免int的符号位捣乱。Java没有无符号类型遇到高位移位、掩码操作时把当成默认选择。第五凡是涉及length、size、边界判断的代码先想清楚是字段还是方法、是包含还是不包含。Java数组的length是字段C数组传参退化成指针List的size()是方法String的length()是方法——一不留神就串台。我个人的体会是操作符这种东西看起来是基础得不能再基础的知识但恰恰是语言设计哲学的浓缩。C给你的是接近硬件的自由Java给你的是工程化的确定性两者没有高下之分只有场景适配问题。把这两套操作符体系真正搞明白你的语言边界感会强很多写多语言项目时也能少很多明明语法一样为什么行为不一样的困惑。希望这篇整理能帮你把这一块地基打得再扎实一点。