编程进阶网 编程进阶网
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • C语言入门精通

  • Cpp入门到精通

  • Java入门精通

    • README
    • 入门教程

      • README
      • 基础语法
      • 数据类型
      • 运算符
        • 3.1 运算符介绍
          • 3.1.1 运算符由来
          • 3.1.2 运算符本质
          • 3.1.3 常见运算符
          • 3.1.4 综合案例:运算符分类速查工具
          • 3.1.5 训练题
        • 3.2 算术运算符
          • 3.2.1 加减乘除
          • 3.2.2 取模
          • 3.2.3 递增递减
          • 3.2.4 字符串拼接
          • 3.2.5 综合案例:时间转换计算器
          • 3.2.6 算术运算符训练题
        • 3.3 赋值运算符
          • 3.3.1 赋值案例
          • 3.3.2 复合赋值隐含转换
          • 3.3.3 赋值运算符训练题
        • 3.4 比较运算符
          • 3.4.1 比较案例
          • 3.4.2 equals和==区别
          • 3.4.3 比较运算符训练题
        • 3.5 逻辑运算符
          • 3.5.1 逻辑非
          • 3.5.2 逻辑与
          • 3.5.3 逻辑或
          • 3.5.4 短路特性
          • 3.5.5 综合案例:用户登录验证器
          • 3.5.6 逻辑运算符训练题
        • 3.6 位运算符
          • 3.6.1 综合案例:位运算权限管理器
          • 3.6.2 位运算符训练题
        • 3.7 运算符优先级
          • 3.7.1 综合案例:优先级陷阱检测器
          • 3.7.2 训练题
        • 3.8 instanceof运算符
          • 3.8.1 instanceof介绍
          • 3.8.2 基本用法
          • 3.8.3 模式匹配(JDK16+)
          • 3.8.4 综合案例:多态类型识别器
          • 3.8.5 instanceof训练题
        • 3.9 三元运算符
          • 3.9.1 综合案例:成绩等级评定器
          • 3.9.2 训练题
      • 字符串和数组
      • 流程语句
      • 函数方法
      • 类和对象
      • 继承和多态
      • 接口和抽象类
      • 异常处理
      • 集合框架
      • IO流和File
      • 线程和锁
      • 泛型
      • 注解和反射
    • 综合案例

    • 专栏博客

  • Go入门到精通

  • JavaScript入门

  • CodeX
  • Java入门精通
  • 入门教程
杨充
2026-04-07
目录

运算符

# 03.运算符

# 目录介绍

  • 3.1 运算符介绍
    • 3.1.1 运算符由来
    • 3.1.2 运算符本质
    • 3.1.3 常见运算符
    • 3.1.4 综合案例:运算符分类速查工具
    • 3.1.5 训练题
  • 3.2 算术运算符
    • 3.2.1 加减乘除
    • 3.2.2 取模
    • 3.2.3 递增递减
    • 3.2.4 字符串拼接
    • 3.2.5 综合案例:时间转换计算器
    • 3.2.6 算术运算符训练题
  • 3.3 赋值运算符
    • 3.3.1 赋值案例
    • 3.3.2 复合赋值隐含转换
    • 3.3.3 赋值运算符训练题
  • 3.4 比较运算符
    • 3.4.1 比较案例
    • 3.4.2 equals和==区别
    • 3.4.3 比较运算符训练题
  • 3.5 逻辑运算符
    • 3.5.1 逻辑非
    • 3.5.2 逻辑与
    • 3.5.3 逻辑或
    • 3.5.4 短路特性
    • 3.5.5 综合案例:用户登录验证器
    • 3.5.6 逻辑运算符训练题
  • 3.6 位运算符
    • 3.6.1 综合案例:位运算权限管理器
    • 3.6.2 位运算符训练题
  • 3.7 运算符优先级
    • 3.7.1 综合案例:优先级陷阱检测器
    • 3.7.2 训练题
  • 3.8 instanceof运算符
    • 3.8.1 instanceof介绍
    • 3.8.2 基本用法
    • 3.8.3 模式匹配(JDK16+)
    • 3.8.4 综合案例:多态类型识别器
    • 3.8.5 instanceof训练题
  • 3.9 三元运算符
    • 3.9.1 综合案例:成绩等级评定器
    • 3.9.2 训练题

# 3.1 运算符介绍

# 3.1.1 运算符由来

起源:数学与逻辑的抽象。运算符的概念源于数学(+, -, *, /, =)和形式逻辑(&&, ||, !)。

编程语言将这些符号引入,用于操作变量、常量和表达式,执行特定的计算或逻辑功能。

# 3.1.2 运算符本质

运算符的底层原理:运算符在编译后会转化为对应的字节码指令。JVM 提供了专门的算术指令来处理不同数据类型的运算:

数据类型 加 减 乘 除 取模
int iadd isub imul idiv irem
long ladd lsub lmul ldiv lrem
float fadd fsub fmul fdiv frem
double dadd dsub dmul ddiv drem

注意:JVM 没有专门的 byte、short、char 运算指令,这些类型参与运算时会先提升为 int(使用 i2b、i2s 等指令转回)。这就是为什么 byte + byte 结果是 int 的根本原因。

对比 C++:C++ 中运算符可以被重载(operator+),Java 中不支持运算符重载(唯一的例外是 + 用于字符串拼接,这是语言内置的)。

疑惑:Java 为什么不支持运算符重载?

答疑:Java 的设计哲学是"简单明确"。Gosling 认为 C++ 的运算符重载虽然灵活,但容易被滥用——当你看到 a + b 时,如果运算符被重载,你无法确定它做了什么(可能是连接数据库、发送网络请求...)。Java 只允许 + 用于 String 拼接,保证了运算符的行为是可预测的。

结果展示:这个设计决策有争议。Kotlin 和 Scala 都运行在 JVM 上,但它们都支持运算符重载。Kotlin 用 operator fun 关键字明确标记,比 C++ 更加节制。这说明运算符重载本身不是问题,关键是语言如何约束它的使用。

# 3.1.3 常见运算符

运算符类型 作用
算术运算符 用于处理四则运算
赋值运算符 用于将表达式的值赋给变量
比较运算符 用于表达式的比较,返回 boolean 值
逻辑运算符 用于根据表达式的值返回 boolean 值
位运算符 用于对二进制位进行操作
三元运算符 简洁的条件表达式
instanceof 判断对象是否是某个类型的实例

# 3.1.4 综合案例:运算符分类速查工具

编写一个程序,接受用户输入的运算符符号,输出该运算符的分类、用途和对应的 JVM 字节码指令。

import java.util.Scanner;

public class OperatorLookup {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入一个运算符(如 +, ==, &&, >>):");
        String op = sc.nextLine().trim();

        System.out.println("\n===== 运算符查询结果 =====");
        switch (op) {
            case "+":
                printInfo("算术运算符", "加法 / 字符串拼接", "iadd(int), ladd(long), dadd(double)");
                System.out.println("  特殊说明: + 是Java唯一被\"重载\"的运算符,用于String拼接");
                break;
            case "-": printInfo("算术运算符", "减法", "isub, lsub, dsub"); break;
            case "*": printInfo("算术运算符", "乘法", "imul, lmul, dmul"); break;
            case "/": printInfo("算术运算符", "除法", "idiv, ldiv, ddiv"); break;
            case "%": printInfo("算术运算符", "取模", "irem, lrem, drem"); break;
            case "++": printInfo("算术运算符", "自增", "iinc(局部变量优化)"); break;
            case "=": printInfo("赋值运算符", "赋值", "istore, astore等"); break;
            case "+=": printInfo("复合赋值运算符", "加后赋值(含隐式转换)", "iadd + i2b/i2s(如需)"); break;
            case "==": printInfo("比较运算符", "相等比较", "if_icmpeq(int), if_acmpeq(引用)"); break;
            case "!=": printInfo("比较运算符", "不等比较", "if_icmpne(int)"); break;
            case "&&": printInfo("逻辑运算符", "短路与", "条件跳转指令组合"); break;
            case "||": printInfo("逻辑运算符", "短路或", "条件跳转指令组合"); break;
            case "&": printInfo("位运算/逻辑运算", "按位与/非短路与", "iand"); break;
            case "|": printInfo("位运算/逻辑运算", "按位或/非短路或", "ior"); break;
            case "^": printInfo("位运算符", "按位异或", "ixor"); break;
            case "~": printInfo("位运算符", "按位取反", "iconst_m1 + ixor"); break;
            case "<<": printInfo("位运算符", "左移", "ishl"); break;
            case ">>": printInfo("位运算符", "有符号右移", "ishr"); break;
            case ">>>": printInfo("位运算符", "无符号右移(Java特有)", "iushr"); break;
            case "instanceof": printInfo("类型判断运算符", "判断对象类型", "instanceof指令"); break;
            case "?:": printInfo("三元运算符", "条件表达式", "条件跳转指令组合"); break;
            default: System.out.println("  未收录的运算符: " + op);
        }

        // 展示运算符分类汇总
        System.out.println("\n===== 运算符分类汇总 =====");
        String[][] categories = {
            {"算术运算符", "+  -  *  /  %  ++  --"},
            {"赋值运算符", "=  +=  -=  *=  /=  %=  &=  |=  ^=  <<=  >>=  >>>="},
            {"比较运算符", "==  !=  >  <  >=  <="},
            {"逻辑运算符", "&&  ||  !  &  |"},
            {"位运算符",   "&  |  ^  ~  <<  >>  >>>"},
            {"三元运算符", "? :"},
            {"类型运算符", "instanceof"},
        };
        for (String[] cat : categories) {
            System.out.printf("  %-10s: %s%n", cat[0], cat[1]);
        }

        sc.close();
    }

    static void printInfo(String category, String usage, String bytecode) {
        System.out.println("  分类: " + category);
        System.out.println("  用途: " + usage);
        System.out.println("  字节码: " + bytecode);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

# 3.1.5 训练题

  1. 填空题:Java 中唯一被"重载"的运算符是 ___,它用于 ___ 拼接。Java 不支持用户自定义运算符重载。

  2. 选择题:以下关于运算符底层原理的说法,正确的是?

    • A. byte + byte 结果是 byte B. JVM 有专门的 byte 运算指令 C. byte + byte 结果是 int D. Java 支持运算符重载
  3. 思考题:Java 不支持运算符重载,而 Kotlin、Scala 支持。你认为运算符重载的利弊各是什么?在什么场景下运算符重载是有价值的?(如复数运算、矩阵运算)

# 3.2 算术运算符

作用:用于处理四则运算

运算符 术语 示例 结果
+ 加 10 + 5 15
- 减 10 - 5 5
* 乘 10 * 5 50
/ 除 10 / 3 3(整数除法)
% 取模 10 % 3 1
++ 自增 a++ / ++a
-- 自减 a-- / --a

# 3.2.1 加减乘除

public class Main {
    public static void main(String[] args) {
        int a = 10, b = 3;
        System.out.println(a + b);  // 13
        System.out.println(a - b);  // 7
        System.out.println(a * b);  // 30
        System.out.println(a / b);  // 3(整数除法,截断小数)

        // 要得到小数结果,至少一个操作数是浮点类型
        System.out.println((double) a / b);  // 3.3333...
        System.out.println(a / (double) b);  // 3.3333...

        // 除数不能为0
        // System.out.println(a / 0);  // ArithmeticException
        System.out.println(10.0 / 0);  // Infinity(浮点除以0得无穷大)
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 3.2.2 取模

System.out.println(10 % 3);   // 1
System.out.println(-10 % 3);  // -1(结果符号与被除数一致)
System.out.println(10 % -3);  // 1

// Java 浮点数也可以取模(C++ 不行)
System.out.println(10.5 % 3); // 1.5
1
2
3
4
5
6

取模运算的实际应用:

// 1. 判断奇偶
boolean isEven = (num % 2 == 0);

// 2. 循环数组(环形缓冲区)
int[] buffer = new int[10];
int index = 0;
for (int i = 0; i < 100; i++) {
    buffer[index % buffer.length] = i;  // 索引在 0-9 之间循环
    index++;
}

// 3. 时间转换
int totalSeconds = 3661;
int hours = totalSeconds / 3600;           // 1
int minutes = (totalSeconds % 3600) / 60;  // 1
int seconds = totalSeconds % 60;           // 1
System.out.printf("%02d:%02d:%02d%n", hours, minutes, seconds);  // 01:01:01

// 4. 分页计算
int totalItems = 23;
int pageSize = 5;
int totalPages = (totalItems + pageSize - 1) / pageSize;  // 5(向上取整)
// 或者:int totalPages = (int) Math.ceil((double) totalItems / pageSize);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 3.2.3 递增递减

int a = 10;
int b = ++a;  // 先加再赋值,a=11, b=11
System.out.println("a=" + a + ", b=" + b);

int c = 10;
int d = c++;  // 先赋值再加,c=11, d=10
System.out.println("c=" + c + ", d=" + d);
1
2
3
4
5
6
7

# 3.2.4 字符串拼接

字符串拼接的底层原理:Java 编译器会将 + 字符串拼接优化为 StringBuilder.append() 调用。例如 "a" + b + "c" 会被编译为 new StringBuilder("a").append(b).append("c").toString()。但在循环中,每次迭代编译器都会创建新的 StringBuilder 对象,因此循环拼接应手动使用 StringBuilder。JDK 9+ 引入了 invokedynamic 指令(StringConcatFactory)进一步优化字符串拼接性能。

Java 中 + 运算符被重载用于字符串拼接:

String name = "张三";
int age = 25;
System.out.println("姓名:" + name + ",年龄:" + age);
// 输出:姓名:张三,年龄:25

// 注意运算顺序
System.out.println(1 + 2 + "abc");   // "3abc"(先算1+2=3,再拼接)
System.out.println("abc" + 1 + 2);   // "abc12"(先拼接"abc1",再拼接"abc12")
1
2
3
4
5
6
7
8

JDK 9+ 字符串拼接优化(invokedynamic):

JDK 9 之前,+ 拼接被编译为 StringBuilder.append() 链。JDK 9 引入了 invokedynamic 指令调用 StringConcatFactory,由 JVM 在运行时选择最优拼接策略(可能是 StringBuilder,也可能是直接字节数组拼接),性能更好且生成的字节码更短。

// JDK 8 编译后
new StringBuilder().append("姓名:").append(name).append(",年龄:").append(age).toString();

// JDK 9+ 编译后(伪代码)
invokedynamic makeConcatWithConstants("姓名:\u0001,年龄:\u0001", name, age)
// JVM 运行时决定最优实现
1
2
3
4
5
6

# 3.2.5 综合案例:时间转换计算器

编写一个程序,综合运用加减乘除、取模、递增递减和字符串拼接,实现秒数与时分秒的相互转换。

import java.util.Scanner;

public class TimeConverter {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入总秒数:");
        int totalSeconds = sc.nextInt();

        // 使用除法和取模转换
        int hours = totalSeconds / 3600;
        int minutes = (totalSeconds % 3600) / 60;
        int seconds = totalSeconds % 60;

        // 字符串拼接输出
        String timeStr = hours + "小时" + minutes + "分" + seconds + "秒";
        System.out.println(totalSeconds + "秒 = " + timeStr);
        System.out.printf("格式化输出: %02d:%02d:%02d%n", hours, minutes, seconds);

        // 递增递减演示:倒计时
        System.out.println("\n===== 倒计时演示(最后5秒) =====");
        int countdown = 5;
        while (countdown > 0) {
            System.out.println("  " + countdown-- + "...");  // 后置递减
        }
        System.out.println("  时间到!");

        // 整数除法 vs 浮点除法对比
        System.out.println("\n===== 除法对比 =====");
        int a = 7, b = 2;
        System.out.println("整数除法: " + a + "/" + b + " = " + (a / b));           // 3
        System.out.println("浮点除法: " + a + "/" + b + " = " + ((double) a / b));   // 3.5
        System.out.println("取模运算: " + a + "%" + b + " = " + (a % b));           // 1

        // 分页计算(实际开发常用)
        int totalItems = 23;
        int pageSize = 5;
        int totalPages = (totalItems + pageSize - 1) / pageSize;  // 向上取整技巧
        System.out.println("\n===== 分页计算 =====");
        System.out.println("总条数: " + totalItems + ", 每页: " + pageSize + ", 总页数: " + totalPages);

        // 前置++和后置++对比
        System.out.println("\n===== ++前置 vs 后置 =====");
        int x = 10;
        int r1 = x++;          // r1=10, x=11
        int r2 = ++x;          // x=12, r2=12
        int r3 = x++ + ++x;    // x++(12,x=13) + ++x(14,x=14) = 26
        System.out.println("x=" + x + ", r1=" + r1 + ", r2=" + r2 + ", r3=" + r3);

        sc.close();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# 3.2.6 算术运算符训练题

训练1:计算 (int)(10.0 / 3) 和 10 / 3 的结果分别是什么?它们的计算过程有什么区别?

训练2:以下代码的输出是什么?请逐步分析:

int x = 5;
int result = x++ + ++x + x-- + --x;
System.out.println(result);  // ?
System.out.println(x);       // ?
1
2
3
4

训练3:在循环中拼接字符串,分别用 + 和 StringBuilder 两种方式,对比 10000 次循环的耗时差异。

思考:为什么 Java 不像 C++ 那样支持运算符重载?运算符重载有什么潜在的问题?

# 3.3 赋值运算符

# 3.3.1 赋值案例

int a = 10;
a += 2;   // a = a + 2 = 12
a -= 3;   // a = a - 3 = 9
a *= 2;   // a = a * 2 = 18
a /= 3;   // a = a / 3 = 6
a %= 4;   // a = a % 4 = 2
System.out.println(a);  // 2
1
2
3
4
5
6
7

# 3.3.2 复合赋值隐含转换

复合赋值运算符会自动进行强制类型转换:

byte b = 10;
// b = b + 1;    // 编译错误!b + 1 结果是 int
b += 1;          // OK!等价于 b = (byte)(b + 1)

short s = 100;
// s = s + 1;    // 编译错误!
s += 1;          // OK!自动强制转换
1
2
3
4
5
6
7

疑惑:为什么 b = b + 1 编译报错,而 b += 1 却可以?

答疑:Java 的运算规则规定,byte、short 参与算术运算时会先自动提升为 int。所以 b + 1 的结果是 int 类型,赋给 byte 变量需要强制转换。但 b += 1 是复合赋值运算符,Java 语言规范(JLS §15.26.2)规定它隐含了强制类型转换,等价于 b = (byte)(b + 1)。

论证:这个设计是语言的便利性考虑。如果 += 不隐含转换,那每次对 byte/short 变量做运算都需要手动转换,代码会非常繁琐。但这也可能隐藏溢出问题:

byte b = 127;
b += 1;  // 不报错!但 b = -128(溢出),等价于 b = (byte)(127 + 1)
1
2

# 3.3.3 赋值运算符训练题

训练1:以下代码能编译通过吗?如果能,结果是什么?

short s = 1;
s = s + 1;      // ①
s += 1;          // ②
s = (short)(s + 1); // ③
1
2
3
4

思考:a += b 和 a = a + b 在所有情况下都等价吗?什么时候会有区别?

# 3.4 比较运算符

# 3.4.1 比较案例

比较运算符的结果是 boolean 类型:

int a = 10, b = 20;
System.out.println(a == b);   // false
System.out.println(a != b);   // true
System.out.println(a > b);    // false
System.out.println(a < b);    // true
System.out.println(a >= b);   // false
System.out.println(a <= b);   // true
1
2
3
4
5
6
7

# 3.4.2 equals和==区别

这是 Java 中非常重要的知识点:

// 基本类型:== 比较值
int a = 10, b = 10;
System.out.println(a == b);  // true

// 引用类型:== 比较地址,equals 比较内容
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2);      // false(不同对象,地址不同)
System.out.println(s1.equals(s2)); // true(内容相同)

// 字符串常量池的特殊情况
String s3 = "hello";
String s4 = "hello";
System.out.println(s3 == s4);      // true(常量池中同一个对象)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

对比 C++:C++ 中 == 可以被重载(如 std::string 重载了 == 比较内容),Java 中 == 对于对象始终比较地址,比较内容必须用 equals。

Integer 缓存池的陷阱:

Integer a = 127, b = 127;
System.out.println(a == b);    // true(缓存池中的同一个对象)

Integer c = 128, d = 128;
System.out.println(c == d);    // false(超出缓存范围,是不同对象)
System.out.println(c.equals(d)); // true(内容相同)
1
2
3
4
5
6

Integer 在 -128 到 127 范围内有缓存(IntegerCache),自动装箱时会复用缓存中的对象。超出范围则每次创建新对象。这是面试中的经典考点。

# 3.4.3 比较运算符训练题

训练1:以下代码分别输出什么?请解释原因:

String s1 = "hello";
String s2 = "hel" + "lo";
String s3 = new String("hello");
String s4 = s3.intern();

System.out.println(s1 == s2);   // ?
System.out.println(s1 == s3);   // ?
System.out.println(s1 == s4);   // ?
1
2
3
4
5
6
7
8

训练2:编写一个方法,正确比较两个可能为 null 的字符串是否相等(避免 NullPointerException)。

思考:为什么 Java 建议使用 "literal".equals(variable) 而不是 variable.equals("literal")?

# 3.5 逻辑运算符

# 3.5.1 逻辑非

boolean a = true;
System.out.println(!a);   // false
System.out.println(!!a);  // true
1
2
3

# 3.5.2 逻辑与

System.out.println(true && true);   // true
System.out.println(true && false);  // false
System.out.println(false && false); // false
1
2
3

# 3.5.3 逻辑或

System.out.println(true || false);  // true
System.out.println(false || false); // false
1
2

# 3.5.4 短路特性

&& 和 || 具有短路特性:

int a = 10;
// && 短路:第一个为 false,不会执行第二个
if (false && (++a > 0)) {}
System.out.println(a);  // 10(++a 没有执行)

// || 短路:第一个为 true,不会执行第二个
if (true || (++a > 0)) {}
System.out.println(a);  // 10(++a 没有执行)
1
2
3
4
5
6
7
8

Java 也有非短路的 & 和 |(用于逻辑运算时不短路),但实际开发中很少使用。

# 3.5.5 综合案例:用户登录验证器

编写一个程序,综合运用逻辑与、逻辑或、逻辑非和短路特性,实现一个用户登录验证系统。

import java.util.Scanner;

public class LoginValidator {
    // 模拟数据库中的用户信息
    static final String VALID_USERNAME = "admin";
    static final String VALID_PASSWORD = "123456";
    static final int MAX_ATTEMPTS = 3;
    static final boolean SYSTEM_MAINTENANCE = false;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int attempts = 0;
        boolean loggedIn = false;

        System.out.println("===== 用户登录系统 =====");

        // 短路或: 系统维护时直接拒绝
        if (SYSTEM_MAINTENANCE || false) {  // 短路特性: 第一个为true则不检查第二个
            System.out.println("系统维护中,请稍后再试");
            return;
        }

        while (!loggedIn && attempts < MAX_ATTEMPTS) {
            System.out.print("用户名: ");
            String username = sc.nextLine();
            System.out.print("密码: ");
            String password = sc.nextLine();

            attempts++;

            // 短路与:先判断非空,再判断内容(避免NPE)
            boolean usernameValid = username != null && !username.isEmpty() && username.equals(VALID_USERNAME);
            boolean passwordValid = password != null && !password.isEmpty() && password.equals(VALID_PASSWORD);

            if (usernameValid && passwordValid) {
                loggedIn = true;
                System.out.println("登录成功! 欢迎 " + username);
            } else {
                int remaining = MAX_ATTEMPTS - attempts;
                // 逻辑非
                System.out.println("登录失败! " + (!usernameValid ? "用户名错误" : "密码错误"));
                // 逻辑运算组合
                if (remaining > 0) {
                    System.out.println("剩余尝试次数: " + remaining);
                } else {
                    System.out.println("账号已锁定!");
                }
            }
            System.out.println();
        }

        // 短路特性安全检查演示
        System.out.println("===== 短路安全检查演示 =====");
        String nullStr = null;
        // 短路与: nullStr为null时不会调用length(),避免NPE
        boolean safe = nullStr != null && nullStr.length() > 5;
        System.out.println("null安全检查结果: " + safe);  // false,不会抛NPE

        // 非短路 & 会导致NPE
        try {
            boolean unsafe = nullStr != null & nullStr.length() > 5;  // 两边都执行!
        } catch (NullPointerException e) {
            System.out.println("非短路&导致NullPointerException!");
        }

        sc.close();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

# 3.5.6 逻辑运算符训练题

训练1:利用短路特性编写一段安全的空指针检查代码:

// 补全代码,使其不会抛出 NullPointerException
String str = null;
if (/* 你的条件 */) {
    System.out.println(str.length());
}
1
2
3
4
5

训练2:以下代码中 a 和 b 最终的值分别是什么?

int a = 0, b = 0;
boolean r1 = (++a > 0) || (++b > 0);
System.out.println("a=" + a + ", b=" + b);  // ?
boolean r2 = (a > 10) && (++b > 0);
System.out.println("a=" + a + ", b=" + b);  // ?
1
2
3
4
5

思考:短路求值在哪些实际开发场景中特别有用?举出至少两个例子。

# 3.6 位运算符

int a = 5, b = 3;  // 5: 0101, 3: 0011
System.out.println(a & b);   // 1  (0001) 按位与
System.out.println(a | b);   // 7  (0111) 按位或
System.out.println(a ^ b);   // 6  (0110) 按位异或
System.out.println(~a);      // -6         按位取反
System.out.println(a << 1);  // 10 (1010) 左移
System.out.println(a >> 1);  // 2  (0010) 有符号右移
System.out.println(a >>> 1); // 2  (0010) 无符号右移
1
2
3
4
5
6
7
8

对比 C++:Java 多了一个 >>> 无符号右移运算符。C++ 中右移运算的符号填充取决于实现,Java 明确区分了 >>(符号填充)和 >>>(零填充)。

位运算的实际应用场景:

// 1. 快速判断奇偶(比 % 2 更高效)
boolean isOdd = (num & 1) == 1;

// 2. 交换两个变量(不使用第三个变量)
a = a ^ b;
b = a ^ b;  // b = (a^b)^b = a
a = a ^ b;  // a = (a^b)^a = b

// 3. 权限管理(Linux 文件权限的原理)
int READ    = 1;  // 001
int WRITE   = 2;  // 010
int EXECUTE = 4;  // 100

int permission = READ | WRITE;        // 011 = 3,具有读写权限
boolean canRead = (permission & READ) != 0;    // true
boolean canExec = (permission & EXECUTE) != 0; // false
permission |= EXECUTE;   // 添加执行权限 → 111 = 7
permission &= ~WRITE;    // 移除写权限    → 101 = 5

// 4. HashMap 计算桶索引(经典应用)
// index = hash & (capacity - 1)  当 capacity 是 2 的幂时等价于 hash % capacity
int index = "hello".hashCode() & (16 - 1);  // 等价于 hashCode % 16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 3.6.1 综合案例:位运算权限管理器

编写一个程序,使用位运算实现一个完整的权限管理系统,演示位与、位或、位异或和移位操作的实际应用。

public class BitPermission {
    // 用位定义权限(每一位代表一种权限)
    static final int NONE    = 0;        // 0000
    static final int READ    = 1;        // 0001
    static final int WRITE   = 1 << 1;   // 0010
    static final int DELETE  = 1 << 2;   // 0100
    static final int ADMIN   = 1 << 3;   // 1000

    // 添加权限(位或)
    static int addPermission(int current, int perm) {
        return current | perm;
    }

    // 移除权限(位与 + 取反)
    static int removePermission(int current, int perm) {
        return current & ~perm;
    }

    // 检查权限(位与)
    static boolean hasPermission(int current, int perm) {
        return (current & perm) == perm;
    }

    // 切换权限(位异或)
    static int togglePermission(int current, int perm) {
        return current ^ perm;
    }

    // 打印权限状态
    static void printPermissions(String name, int perm) {
        System.out.printf("  %s [%s]: R=%b W=%b D=%b A=%b%n", name,
                String.format("%4s", Integer.toBinaryString(perm)).replace(' ', '0'),
                hasPermission(perm, READ),
                hasPermission(perm, WRITE),
                hasPermission(perm, DELETE),
                hasPermission(perm, ADMIN));
    }

    public static void main(String[] args) {
        System.out.println("===== 权限管理系统 =====");

        // 创建不同角色的权限
        int visitor = READ;                                    // 只读
        int editor = READ | WRITE;                             // 读写
        int moderator = READ | WRITE | DELETE;                 // 读写删
        int admin = READ | WRITE | DELETE | ADMIN;             // 全部权限

        printPermissions("游客", visitor);
        printPermissions("编辑", editor);
        printPermissions("版主", moderator);
        printPermissions("管理员", admin);

        // 权限操作演示
        System.out.println("\n===== 权限操作 =====");
        int user = READ;
        System.out.print("初始: "); printPermissions("用户", user);

        user = addPermission(user, WRITE);
        System.out.print("加写: "); printPermissions("用户", user);

        user = addPermission(user, DELETE);
        System.out.print("加删: "); printPermissions("用户", user);

        user = removePermission(user, DELETE);
        System.out.print("去删: "); printPermissions("用户", user);

        user = togglePermission(user, WRITE);
        System.out.print("切写: "); printPermissions("用户", user);  // WRITE被切掉

        // 不用临时变量交换两个数
        System.out.println("\n===== 异或交换 =====");
        int a = 42, b = 99;
        System.out.println("交换前: a=" + a + ", b=" + b);
        a = a ^ b;
        b = a ^ b;  // b = (a^b)^b = a
        a = a ^ b;  // a = (a^b)^a = b
        System.out.println("交换后: a=" + a + ", b=" + b);

        // 2的幂判断
        System.out.println("\n===== 2的幂判断 =====");
        for (int n : new int[]{1, 2, 3, 4, 8, 15, 16, 64, 100}) {
            boolean isPow2 = n > 0 && (n & (n - 1)) == 0;
            System.out.printf("  %3d: %s (二进制: %s)%n", n, isPow2 ? "是2的幂" : "否", Integer.toBinaryString(n));
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

# 3.6.2 位运算符训练题

训练1:用位运算实现一个方法 boolean isPowerOfTwo(int n),判断一个正整数是否是 2 的幂。(提示:2 的幂的二进制只有一个 1)

训练2:不使用临时变量,用异或运算交换两个整数 a 和 b 的值。解释每一步的原理。

训练3:实现一个简单的权限系统:定义 READ=1, WRITE=2, DELETE=4, ADMIN=8 四种权限,编写方法 addPermission、removePermission、hasPermission 使用位运算实现。

思考:为什么 HashMap 要求容量是 2 的幂?hash & (capacity - 1) 和 hash % capacity 有什么关系?

# 3.7 运算符优先级

从高到低:

  1. ()(括号)
  2. ++、--、!、~(一元运算符)
  3. *、/、%
  4. +、-
  5. <<、>>、>>>
  6. <、<=、>、>=、instanceof
  7. ==、!=
  8. &、^、|
  9. &&、||
  10. ? :(三元运算符)
  11. =、+=、-= 等

建议:不确定优先级时使用括号明确运算顺序,提高可读性。

# 3.7.1 综合案例:优先级陷阱检测器

编写一个程序,列举常见的运算符优先级陷阱,展示不加括号和加括号的不同结果。

public class PriorityTrap {
    public static void main(String[] args) {
        System.out.println("===== 运算符优先级陷阱 =====\n");

        // 陷阱1:乘法优先于加法
        int r1 = 2 + 3 * 4;
        System.out.println("陷阱1: 2 + 3 * 4 = " + r1 + " (不是20,而是14)");
        System.out.println("  修正: (2 + 3) * 4 = " + ((2 + 3) * 4));

        // 陷阱2:&& 优先于 ||
        boolean r2 = true || false && false;
        System.out.println("\n陷阱2: true || false && false = " + r2 + " (&&先算)");
        System.out.println("  等价于: true || (false && false) = true");
        System.out.println("  如果想先算||: (true || false) && false = " + ((true || false) && false));

        // 陷阱3:位运算优先级低于比较运算
        int x = 5;
        // boolean r3 = x & 1 == 1;  // 编译错误! 等价于 x & (1 == 1) → x & true → 类型错误
        boolean r3 = (x & 1) == 1;    // 正确写法
        System.out.println("\n陷阱3: x & 1 == 1 编译错误!");
        System.out.println("  修正: (x & 1) == 1 = " + r3);

        // 陷阱4:赋值优先级最低
        int a = 1, b = 2;
        // 意图是 a = b, 判断 a > 0; 实际是 a = (b > 0 的结果)? 不对,Java不允许
        boolean r4 = (a = b) > 0;  // 先赋值a=2,再比较2>0
        System.out.println("\n陷阱4: (a = b) > 0 → a变为" + a + ", 结果=" + r4);

        // 陷阱5:字符串拼接与算术混合
        System.out.println("\n陷阱5: 字符串拼接顺序");
        System.out.println("  1 + 2 + \"abc\" = " + (1 + 2 + "abc"));     // "3abc"
        System.out.println("  \"abc\" + 1 + 2 = " + ("abc" + 1 + 2));     // "abc12"
        System.out.println("  \"abc\" + (1 + 2) = " + ("abc" + (1 + 2))); // "abc3"

        // 总结:优先级速记表
        System.out.println("\n===== 优先级速记(从高到低) =====");
        String[] levels = {
            "1. ()  括号",
            "2. ++  --  !  ~  (一元)",
            "3. *  /  %",
            "4. +  -",
            "5. <<  >>  >>>",
            "6. <  <=  >  >=  instanceof",
            "7. ==  !=",
            "8. &  ^  |  (位运算)",
            "9. &&  ||  (逻辑)",
            "10. ?:  (三元)",
            "11. =  +=  -=  (赋值)"
        };
        for (String level : levels) {
            System.out.println("  " + level);
        }
        System.out.println("\n建议: 不确定时加括号,可读性远比简洁重要!");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

# 3.7.2 训练题

  1. 代码题:不运行代码,请预测以下表达式的值:

    int a = 2 + 3 * 4;          // ?
    boolean b = true || false && false;  // ?
    int c = 5 & 3 | 2;          // ?
    
    1
    2
    3
  2. 改错题:以下代码的意图是判断 x 是否在 1~100 之间,但写法有误,请找出并修正:

    int x = 50;
    if (1 < x < 100) {  // 这行对吗?
        System.out.println("在范围内");
    }
    
    1
    2
    3
    4
  3. 思考题:为什么 Java(和大多数编程语言)要定义运算符优先级?如果所有运算符优先级相同、严格从左到右计算,会有什么影响?

# 3.8 instanceof运算符

# 3.8.1 instanceof介绍

instanceof 是 Java 特有的运算符,用于判断一个对象是否是某个类(或接口)的实例。

# 3.8.2 基本用法

String str = "Hello";
System.out.println(str instanceof String);  // true
System.out.println(str instanceof Object);  // true

Object obj = new Integer(10);
System.out.println(obj instanceof Integer); // true
System.out.println(obj instanceof String);  // false

// null 不是任何类的实例
System.out.println(null instanceof String); // false
1
2
3
4
5
6
7
8
9
10

# 3.8.3 模式匹配(JDK16+)

JDK 16 引入了 instanceof 模式匹配,可以在判断的同时完成类型转换:

Object obj = "Hello World";

// 传统写法
if (obj instanceof String) {
    String str = (String) obj;
    System.out.println(str.length());
}

// JDK 16+ 模式匹配写法
if (obj instanceof String str) {
    System.out.println(str.length());  // 直接使用 str
}
1
2
3
4
5
6
7
8
9
10
11
12

对比 C++:C++ 使用 dynamic_cast 进行运行时类型转换,失败返回 nullptr。Java 的 instanceof 更加简洁安全。

# 3.8.4 综合案例:多态类型识别器

编写一个程序,使用 instanceof 对不同类型的对象进行分类处理,并演示模式匹配的优势。

import java.util.ArrayList;
import java.util.List;

public class TypeIdentifier {
    // 定义一个简单的图形类层次
    static abstract class Shape {
        abstract double area();
    }

    static class Circle extends Shape {
        double radius;
        Circle(double r) { this.radius = r; }
        double area() { return Math.PI * radius * radius; }
    }

    static class Rectangle extends Shape {
        double width, height;
        Rectangle(double w, double h) { this.width = w; this.height = h; }
        double area() { return width * height; }
    }

    static class Triangle extends Shape {
        double base, height;
        Triangle(double b, double h) { this.base = b; this.height = h; }
        double area() { return 0.5 * base * height; }
    }

    // 传统写法:instanceof + 强制转换
    static String describeTraditional(Object obj) {
        if (obj instanceof Circle) {
            Circle c = (Circle) obj;
            return "圆形: 半径=" + c.radius + ", 面积=" + String.format("%.2f", c.area());
        } else if (obj instanceof Rectangle) {
            Rectangle r = (Rectangle) obj;
            return "矩形: " + r.width + "×" + r.height + ", 面积=" + String.format("%.2f", r.area());
        } else if (obj instanceof Triangle) {
            Triangle t = (Triangle) obj;
            return "三角形: 底=" + t.base + " 高=" + t.height + ", 面积=" + String.format("%.2f", t.area());
        } else if (obj instanceof String) {
            return "字符串: \"" + obj + "\"";
        } else if (obj == null) {
            return "null对象";
        }
        return "未知类型: " + obj.getClass().getSimpleName();
    }

    // JDK16+ 模式匹配写法(更简洁)
    static String describeModern(Object obj) {
        if (obj instanceof Circle c) {
            return "圆形: 半径=" + c.radius + ", 面积=" + String.format("%.2f", c.area());
        } else if (obj instanceof Rectangle r) {
            return "矩形: " + r.width + "×" + r.height + ", 面积=" + String.format("%.2f", r.area());
        } else if (obj instanceof Triangle t) {
            return "三角形: 底=" + t.base + " 高=" + t.height + ", 面积=" + String.format("%.2f", t.area());
        } else if (obj instanceof String s) {
            return "字符串: \"" + s + "\", 长度=" + s.length();
        } else if (obj == null) {
            return "null对象";
        }
        return "未知类型: " + obj.getClass().getSimpleName();
    }

    public static void main(String[] args) {
        List<Object> items = new ArrayList<>();
        items.add(new Circle(5));
        items.add(new Rectangle(4, 6));
        items.add(new Triangle(3, 8));
        items.add("Hello Java");
        items.add(42);
        items.add(null);

        System.out.println("===== 类型识别(传统写法) =====");
        for (Object item : items) {
            System.out.println("  " + describeTraditional(item));
        }

        System.out.println("\n===== 类型识别(模式匹配JDK16+) =====");
        for (Object item : items) {
            System.out.println("  " + describeModern(item));
        }

        // instanceof 与继承关系
        System.out.println("\n===== instanceof与继承 =====");
        Shape shape = new Circle(3);
        System.out.println("Circle instanceof Shape: " + (shape instanceof Shape));     // true
        System.out.println("Circle instanceof Circle: " + (shape instanceof Circle));   // true
        System.out.println("Circle instanceof Object: " + (shape instanceof Object));   // true
        System.out.println("Circle instanceof Rectangle: " + (shape instanceof Rectangle)); // false

        // null 判断
        System.out.println("\n===== null判断 =====");
        System.out.println("null instanceof Object: " + (null instanceof Object));     // false
        System.out.println("null instanceof String: " + (null instanceof String));     // false
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

# 3.8.5 instanceof训练题

训练1:编写方法 String describeType(Object obj),使用 instanceof 模式匹配(JDK16+)判断参数类型(String、Integer、Double、List、null),返回类型描述和相关信息。

训练2:以下代码能编译通过吗?输出什么?

Integer num = null;
System.out.println(num instanceof Integer);  // ?
System.out.println(num instanceof Object);   // ?
1
2
3

思考:instanceof 在多态场景下,检查的是编译类型还是运行时类型?以下代码输出什么?

Object obj = "Hello";
System.out.println(obj instanceof String);  // ?
System.out.println(obj instanceof Object);  // ?
1
2
3

# 3.9 三元运算符

int a = 10, b = 20;
int max = (a > b) ? a : b;
System.out.println("较大值:" + max);  // 20

// 可以嵌套,但不建议过度嵌套
String level = (score >= 90) ? "优秀" : (score >= 60) ? "及格" : "不及格";
1
2
3
4
5
6

三元运算符的类型推断规则:

// 三元运算符的两个分支必须类型兼容
int a = 10;
double b = 3.14;
// 当两个分支类型不同时,会自动类型提升
double result = true ? a : b;  // int 提升为 double
System.out.println(result);     // 10.0

// 一个经典陷阱
Object obj = true ? new Integer(1) : new Double(2.0);
System.out.println(obj);  // 1.0(不是1!因为 Integer 被提升为 Double)
// 原因:编译器将两个分支统一为 double 类型

// 另一个陷阱:自动拆箱可能导致 NPE
Integer x = null;
int y = true ? x : 0;  // NullPointerException!x 拆箱时为 null
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 3.9.1 综合案例:成绩等级评定器

编写一个程序,使用三元运算符实现成绩等级评定,并演示嵌套三元运算和类型推断陷阱。

import java.util.Scanner;

public class GradeEvaluator {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入成绩(0-100):");
        int score = sc.nextInt();

        // 基础三元运算
        String passOrFail = score >= 60 ? "及格" : "不及格";
        System.out.println("结果: " + passOrFail);

        // 嵌套三元运算(不建议超过3层)
        String grade = score >= 90 ? "A(优秀)"
                     : score >= 80 ? "B(良好)"
                     : score >= 70 ? "C(中等)"
                     : score >= 60 ? "D(及格)"
                     : "F(不及格)";
        System.out.println("等级: " + grade);

        // 三元运算求最大值
        int a = 15, b = 28, c = 12;
        int max = (a > b) ? (a > c ? a : c) : (b > c ? b : c);
        System.out.println("\n三个数(" + a + "," + b + "," + c + ")的最大值: " + max);

        // 三元运算求绝对值
        int num = -42;
        int abs = num >= 0 ? num : -num;
        System.out.println(num + " 的绝对值: " + abs);

        // 类型推断陷阱
        System.out.println("\n===== 三元运算陷阱 =====");

        // 陷阱1: 类型提升
        int intVal = 1;
        double doubleVal = 2.0;
        // 两个分支类型不同时,int会提升为double
        Object result1 = true ? intVal : doubleVal;
        System.out.println("true ? int : double = " + result1 + " (类型: " + result1.getClass().getSimpleName() + ")");

        // 陷阱2: 包装类自动拆箱 → NPE
        System.out.println("\n陷阱2: null自动拆箱");
        Integer nullInt = null;
        try {
            int danger = true ? nullInt : 0;  // nullInt拆箱时NPE!
        } catch (NullPointerException e) {
            System.out.println("  NullPointerException! null的Integer拆箱失败");
        }
        // 安全写法
        int safe = true ? (nullInt != null ? nullInt : 0) : 0;
        System.out.println("  安全写法结果: " + safe);

        // 陷阱3: char与int的混合
        char ch = 'X';
        System.out.println("\ntrue ? 'X' : 0 = " + (true ? ch : 0));   // 88 (int)
        System.out.println("true ? 'X' : \"\" = " + (true ? ch : "")); // X (String)

        sc.close();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

# 3.9.2 训练题

  1. 代码题:用三元运算符实现一个方法 String getSign(int num),根据数值返回 "正数"、"负数" 或 "零"。

  2. 改错题:以下代码有什么问题?

    Object result = true ? new Integer(1) : new Double(2.0);
    System.out.println(result);  // 期望输出 1,实际输出什么?
    
    1
    2
  3. 思考题:三元运算符 ? : 可以嵌套使用,但过度嵌套会降低可读性。在实际项目中,嵌套超过几层时应改用 if-else?为什么?

上次更新: 2026/06/10, 11:13:41
数据类型
字符串和数组

← 数据类型 字符串和数组→

最近更新
01
信号崩溃快速排查
06-15
02
CoreDump破案
06-15
03
perf火焰图实战
06-15
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式