八、综合练习题

8.1 基础练习

练习1:温度转换器

编写程序实现摄氏度和华氏度的相互转换
公式:F = C * 9/5 + 32
     C = (F - 32) * 5/9

练习2:计算器

编写一个简单的计算器程序,支持加减乘除四则运算
要求:
1. 输入两个数字和一个运算符
2. 输出计算结果
3. 处理除数为0的情况

练习3:判断三角形类型

输入三角形的三条边长,判断:
1. 是否能构成三角形
2. 如果能,判断是等边、等腰还是普通三角形

练习4:打印菱形

输入一个奇数n,打印n行的菱形
例如n=5:
    *
   ***
  *****
   ***
    *

练习5:数组去重

给定一个整数数组,去除重复元素,返回新数组
例如:[1, 2, 2, 3, 4, 4, 5] -> [1, 2, 3, 4, 5]

8.2 进阶练习

练习6:杨辉三角

打印n行杨辉三角
例如n=5:
    1
   1 1
  1 2 1
 1 3 3 1
1 4 6 4 1

练习7:字符串反转(不使用reverse方法)

实现字符串反转功能,不能使用StringBuilder的reverse方法
例如:"Hello" -> "olleH"

练习8:找出数组中第二大的数

给定一个整数数组,找出第二大的数
例如:[3, 1, 4, 1, 5, 9, 2, 6] -> 6

练习9:统计单词出现次数

给定一个字符串,统计每个单词出现的次数
例如:"hello world hello java" 
输出:hello: 2, world: 1, java: 1

练习10:实现简单的学生管理系统

要求:
1. 使用数组存储学生信息(姓名、年龄、成绩)
2. 实现添加、删除、查询、修改功能
3. 实现按成绩排序功能
4. 实现菜单循环

8.3 算法练习

练习11:斐波那契数列

计算斐波那契数列的第n项
F(0) = 0, F(1) = 1
F(n) = F(n-1) + F(n-2)

练习12:最大公约数和最小公倍数

输入两个正整数,计算它们的最大公约数和最小公倍数
提示:使用辗转相除法

练习13:完数判断

判断一个数是否为完数
完数:一个数等于它的所有真因子之和
例如:6 = 1 + 2 + 3

练习14:数组中的最长连续序列

找出数组中最长的连续递增序列的长度
例如:[1, 3, 5, 4, 7] -> 3(3, 4, 5)

练习15:字符串的全排列

输出字符串的所有排列组合
例如:"abc" -> abc, acb, bac, bca, cab, cba

8.4 实战练习

练习16:身份证号码验证

验证18位身份证号码的合法性
要求:
1. 长度必须是18位
2. 前17位必须是数字
3. 最后一位可以是数字或X
4. 验证校验码是否正确

练习17:银行账户系统

实现简单的银行账户系统
功能:
1. 开户(生成账号)
2. 存款
3. 取款
4. 查询余额
5. 转账

练习18:简单的文本编辑器

实现文本编辑器的基本功能
功能:
1. 输入文本
2. 查找文本
3. 替换文本
4. 统计字符数、单词数、行数

练习19:成绩管理系统

实现学生成绩管理系统
功能:
1. 录入学生成绩
2. 计算平均分、最高分、最低分
3. 按成绩排序
4. 查询不及格学生
5. 生成成绩报表

练习20:简单的图书管理系统

实现图书管理系统
功能:
1. 添加图书
2. 删除图书
3. 查询图书(按书名、作者、ISBN)
4. 借书
5. 还书
6. 显示所有图书

九、面试常见问题

9.1 基础概念

Q1:JDK、JRE、JVM的区别是什么?

A:

  • JVM(Java Virtual Machine):Java虚拟机,负责执行Java字节码
  • JRE(Java Runtime Environment):Java运行环境,包含JVM和核心类库,用于运行Java程序
  • JDK(Java Development Kit):Java开发工具包,包含JRE和开发工具(javac、jar等),用于开发Java程序

关系:JDK > JRE > JVM

Q2:Java是编译型语言还是解释型语言?

A:Java是编译型和解释型的混合语言

  1. 编译阶段:Java源代码(.java)被javac编译成字节码(.class)
  2. 解释阶段:JVM解释执行字节码,或通过JIT编译器编译成机器码执行

Q3:为什么Java是跨平台的?

A:

  1. Java源代码编译成平台无关的字节码
  2. 不同操作系统有不同的JVM实现
  3. JVM负责将字节码转换为特定平台的机器码
  4. 实现了"一次编写,到处运行"(Write Once, Run Anywhere)

Q4:Java的基本数据类型有哪些?

A:8种基本数据类型

  • 整数类型:byte(1字节)、short(2字节)、int(4字节)、long(8字节)
  • 浮点类型:float(4字节)、double(8字节)
  • 字符类型:char(2字节)
  • 布尔类型:boolean(1位)

Q5:自动类型转换和强制类型转换的区别?

A:

  • 自动类型转换:小类型自动转换为大类型,不会丢失精度
    • 例如:byte -> short -> int -> long -> float -> double
  • 强制类型转换:大类型转换为小类型,可能丢失精度,需要显式转换
    • 例如:double d = 3.14; int i = (int)d; // i = 3

9.2 运算符和控制流程

Q6:++i和i++的区别?

A:

  • ++i(前置自增):先自增,后使用
    • int i = 5; int j = ++i; // i=6, j=6
  • i++(后置自增):先使用,后自增
    • int i = 5; int j = i++; // i=6, j=5

Q7:==和equals()的区别?

A:

  • ==:比较基本类型的值,比较引用类型的地址
  • equals():比较对象的内容(需要重写equals方法)
String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");

s1 == s2;        // true(指向同一个对象)
s1 == s3;        // false(不同对象)
s1.equals(s3);   // true(内容相同)

Q8:switch支持哪些数据类型?

A:

  • JDK 7之前:byte、short、int、char、枚举
  • JDK 7及以后:增加了String
  • 不支持:long、float、double、boolean

Q9:break和continue的区别?

A:

  • break:跳出整个循环,不再执行后续循环
  • continue:跳过本次循环,继续执行下一次循环

9.3 数组

Q10:数组的特点是什么?

A:

  1. 存储相同类型的数据
  2. 长度固定,创建后不能改变
  3. 内存连续,通过索引快速访问
  4. 索引从0开始

Q11:如何复制数组?

A:有多种方式

  1. 循环复制
  2. System.arraycopy()
  3. Arrays.copyOf()
  4. clone()

注意:直接赋值不是复制,而是引用

Q12:数组越界会发生什么?

A:抛出ArrayIndexOutOfBoundsException异常

预防方法:

  1. 访问前检查索引范围:index >= 0 && index < arr.length
  2. 使用增强for循环遍历
  3. 使用Arrays工具类的方法

9.4 字符串

Q13:String、StringBuilder、StringBuffer的区别?

A:

特性 String StringBuilder StringBuffer
可变性 不可变 可变 可变
线程安全 安全 不安全 安全
性能 较快
使用场景 字符串不变 单线程字符串拼接 多线程字符串拼接

Q14:为什么String是不可变的?

A:

  1. String内部使用final char[]存储数据
  2. 没有提供修改字符数组的方法
  3. 所有"修改"操作都会创建新对象

好处:

  1. 线程安全
  2. 可以缓存hash值
  3. 可以使用字符串常量池

Q15:String str = "hello"和String str = new String(“hello”)的区别?

A:

  • “hello”:在字符串常量池中创建对象
  • new String(“hello”):在堆内存中创建新对象
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");

s1 == s2;  // true(指向常量池中同一个对象)
s1 == s3;  // false(s3在堆中)

Q16:如何判断字符串是否为空?

A:需要同时判断null和空字符串

// 方式1:分别判断
if (str != null && !str.isEmpty()) {
    // 字符串不为空
}

// 方式2:使用工具类(推荐)
if (StringUtils.isNotBlank(str)) {  // Apache Commons Lang
    // 字符串不为空且不是空白
}

Q17:字符串拼接的最佳实践?

A:

  • 少量拼接:使用+运算符
  • 循环拼接:使用StringBuilder
  • 多个字符串拼接:使用String.join()
// 不推荐:循环中使用+
String s = "";
for (int i = 0; i < 1000; i++) {
    s += i;  // 每次都创建新对象
}

// 推荐:使用StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append(i);
}
String s = sb.toString();

9.5 综合问题

Q18:Java中的注释有哪几种?

A:三种注释

  1. 单行注释:// 注释内容
  2. 多行注释:/* 注释内容 */
  3. 文档注释:/** 注释内容 */(可以生成API文档)

Q19:Java命名规范是什么?

A:

  • 类名:大驼峰命名法(UserService)
  • 方法名:小驼峰命名法(getUserName)
  • 变量名:小驼峰命名法(userName)
  • 常量名:全大写,下划线分隔(MAX_SIZE)
  • 包名:全小写,点分隔(com.example.project)

Q20:如何提高代码的可读性?

A:

  1. 使用有意义的变量名和方法名
  2. 添加适当的注释
  3. 保持代码简洁,一个方法只做一件事
  4. 使用空行分隔逻辑块
  5. 遵循代码规范
  6. 避免过深的嵌套
  7. 使用常量代替魔法数字

十、学习检查清单

10.1 开发环境

  • 能够独立安装JDK并配置环境变量
  • 能够验证JDK安装是否成功
  • 能够安装和配置IDEA开发工具
  • 熟悉IDEA的基本操作和常用快捷键
  • 能够创建Java项目和类
  • 能够运行和调试Java程序

10.2 基础语法

  • 理解Java程序的基本结构
  • 掌握Java的三种注释方式
  • 理解标识符和关键字的概念
  • 掌握变量的声明、初始化和使用
  • 理解变量的作用域
  • 掌握常量的定义和使用

10.3 数据类型

  • 掌握8种基本数据类型及其取值范围
  • 理解基本类型和引用类型的区别
  • 掌握自动类型转换的规则
  • 掌握强制类型转换的使用
  • 理解类型转换可能出现的问题

10.4 运算符

  • 掌握算术运算符的使用
  • 理解++和–的前置和后置区别
  • 掌握赋值运算符和复合赋值运算符
  • 掌握比较运算符的使用
  • 掌握逻辑运算符及其短路特性
  • 掌握三元运算符的使用
  • 理解运算符的优先级

10.5 控制流程

  • 掌握if语句的三种形式
  • 掌握switch语句的使用
  • 理解if和switch的选择场景
  • 掌握for循环的使用
  • 掌握while循环的使用
  • 掌握do-while循环的使用
  • 理解三种循环的区别和选择
  • 掌握break和continue的使用
  • 能够使用嵌套循环解决问题

10.6 数组

  • 理解数组的概念和特点
  • 掌握一维数组的声明和初始化
  • 掌握数组元素的访问和修改
  • 掌握数组的遍历方法
  • 掌握数组的常见操作(查找、排序、复制)
  • 掌握二维数组的使用
  • 理解数组的内存结构
  • 能够避免数组越界和空指针异常

10.7 字符串

  • 理解String的不可变性
  • 掌握String的创建方式
  • 掌握String的常用方法
  • 理解==和equals()的区别
  • 掌握字符串的比较、查找、截取、替换
  • 掌握字符串的分割和拼接
  • 理解StringBuilder和StringBuffer的区别
  • 能够选择合适的字符串操作方式

10.8 综合能力

  • 能够编写简单的控制台程序
  • 能够使用循环和数组解决实际问题
  • 能够进行字符串处理
  • 能够调试程序并修复错误
  • 能够阅读和理解他人的代码
  • 养成良好的编码习惯

十一、知识总结

11.1 核心知识点回顾

1. Java开发环境

  • JDK = JRE + 开发工具
  • JRE = JVM + 核心类库
  • 环境变量配置:JAVA_HOME、Path
  • IDEA是目前最流行的Java开发工具

2. Java程序结构

public class ClassName {
    public static void main(String[] args) {
        // 程序入口
    }
}

3. 数据类型体系

数据类型
├── 基本类型(8种)
│   ├── 整数:byte、short、int、long
│   ├── 浮点:float、double
│   ├── 字符:char
│   └── 布尔:boolean
└── 引用类型
    ├── 类
    ├── 接口
    └── 数组

4. 控制流程

控制流程
├── 选择结构
│   ├── if-else
│   └── switch-case
├── 循环结构
│   ├── for
│   ├── while
│   └── do-while
└── 跳转语句
    ├── break
    ├── continue
    └── return

5. 数组操作

  • 声明:int[] arr = new int[5];
  • 初始化:int[] arr = {1, 2, 3, 4, 5};
  • 访问:arr[index]
  • 遍历:for循环、增强for循环
  • 常用操作:查找、排序、复制

6. 字符串处理

  • String:不可变,线程安全
  • StringBuilder:可变,线程不安全,性能好
  • StringBuffer:可变,线程安全,性能较好
  • 常用方法:length()、charAt()、substring()、indexOf()、replace()、split()

11.2 学习方法总结

1. 理论与实践结合

  • 学完一个知识点立即动手实践
  • 通过编写代码加深理解
  • 遇到问题先思考再查资料

2. 循序渐进

  • 从简单到复杂
  • 从单一到综合
  • 不要跳跃式学习

3. 多做练习

  • 完成课后练习题
  • 参加在线编程练习(LeetCode等)
  • 尝试编写小项目

4. 总结归纳

  • 定期复习所学内容
  • 整理知识点思维导图
  • 记录学习笔记和心得

5. 培养编程思维

  • 学会分析问题
  • 学会设计算法
  • 学会优化代码

11.3 常见错误总结

1. 语法错误

  • 忘记分号
  • 括号不匹配
  • 变量未声明就使用
  • 类型不匹配

2. 逻辑错误

  • 循环条件错误
  • 数组越界
  • 整数除法精度丢失
  • 空指针异常

3. 编码习惯问题

  • 变量命名不规范
  • 缺少注释
  • 代码缩进混乱
  • 魔法数字

11.4 下一步学习建议

1. 巩固基础

  • 多做练习题
  • 尝试编写小程序
  • 阅读优秀代码

2. 学习面向对象

  • 类和对象
  • 封装、继承、多态
  • 接口和抽象类
  • 设计模式

3. 学习Java进阶特性

  • 集合框架
  • 异常处理
  • IO流
  • 多线程
  • 反射和注解

4. 学习开发工具

  • Maven/Gradle
  • Git版本控制
  • 单元测试

5. 学习框架

  • Spring
  • Spring Boot
  • MyBatis

11.5 学习资源推荐

1. 官方文档

  • Java官方文档:https://docs.oracle.com/en/java/
  • Java教程:https://docs.oracle.com/javase/tutorial/

2. 在线学习平台

  • LeetCode:算法练习
  • 牛客网:面试题库
  • GitHub:开源项目学习

3. 推荐书籍

  • 《Java核心技术 卷I》:基础必读
  • 《Effective Java》:最佳实践
  • 《Java编程思想》:深入理解

4. 视频教程

  • B站:搜索Java基础教程
  • 慕课网:Java入门课程
  • 极客时间:Java核心技术

11.6 结语

恭喜你完成了Java开发环境与基础语法的学习!这是Java学习之路的第一步,也是最重要的一步。

记住:

  • 编程是一门实践的艺术,多写代码才能提高
  • 遇到问题不要气馁,每个程序员都是从错误中成长的
  • 保持学习的热情,技术在不断更新
  • 养成良好的编码习惯,受益终身

下一步:

  • 完成本章的所有练习题
  • 尝试编写一个小项目(如学生管理系统)
  • 开始学习面向对象编程

加油!你已经迈出了成为Java开发工程师的第一步!


文档信息:

  • 文档名称:01-Java开发环境与基础语法
  • 适用人群:Java零基础学习者
  • 学习时长:建议1-2周
  • 前置知识:无
  • 后续学习:02-面向对象编程基础

版本历史:

  • v1.0 (2024-01-01):初始版本
  • 包含:开发环境、基础语法、数据类型、运算符、控制流程、数组、字符串
  • 代码示例:50+
  • 练习题:20+
  • 面试题:20+

反馈与建议:
如果你在学习过程中遇到问题或有任何建议,欢迎反馈!

十二、扩展知识

12.1 Java代码执行流程详解

完整的执行流程:

热点代码

普通代码

编写Java源代码.java

javac编译器

生成字节码.class

类加载器ClassLoader

字节码验证器

JVM解释器

JIT编译器判断

编译成机器码

解释执行

CPU执行

程序结束

详细说明:

  1. 编译阶段
# 编译Java源文件
javac HelloWorld.java

# 生成字节码文件
HelloWorld.class
  1. 类加载阶段
  • 加载(Loading):读取.class文件
  • 链接(Linking):验证、准备、解析
  • 初始化(Initialization):执行静态代码块
  1. 执行阶段
  • 解释执行:逐行解释字节码
  • JIT编译:将热点代码编译成机器码

12.2 内存管理基础

Java内存结构:

JVM内存结构
├── 堆内存(Heap)
│   ├── 新生代(Young Generation)
│   │   ├── Eden区
│   │   ├── Survivor0区
│   │   └── Survivor1区
│   └── 老年代(Old Generation)
├── 栈内存(Stack)
│   ├── 局部变量
│   ├── 方法参数
│   └── 返回地址
├── 方法区(Method Area)
│   ├── 类信息
│   ├── 常量池
│   └── 静态变量
└── 程序计数器(PC Register)

代码示例:内存分配

public class MemoryDemo {
    // 静态变量:存储在方法区
    static int staticVar = 100;
    
    // 实例变量:存储在堆内存
    int instanceVar = 200;
    
    public static void main(String[] args) {
        // 局部变量:存储在栈内存
        int localVar = 300;
        
        // 对象:存储在堆内存
        MemoryDemo obj = new MemoryDemo();
        
        // 字符串常量:存储在字符串常量池
        String str = "Hello";
        
        System.out.println("静态变量:" + staticVar);
        System.out.println("实例变量:" + obj.instanceVar);
        System.out.println("局部变量:" + localVar);
        System.out.println("字符串:" + str);
    }
}

12.3 Java输入输出基础

Scanner类的使用:

import java.util.Scanner;

public class ScannerDemo {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取整数
        System.out.print("请输入年龄:");
        int age = scanner.nextInt();
        System.out.println("你的年龄是:" + age);
        
        // 读取浮点数
        System.out.print("请输入身高(米):");
        double height = scanner.nextDouble();
        System.out.println("你的身高是:" + height + "米");
        
        // 读取字符串(单词)
        System.out.print("请输入姓名:");
        String name = scanner.next();
        System.out.println("你的姓名是:" + name);
        
        // 清空缓冲区
        scanner.nextLine();
        
        // 读取字符串(整行)
        System.out.print("请输入地址:");
        String address = scanner.nextLine();
        System.out.println("你的地址是:" + address);
        
        // 关闭Scanner
        scanner.close();
    }
}

格式化输出:

public class PrintfDemo {
    public static void main(String[] args) {
        String name = "张三";
        int age = 25;
        double salary = 8888.88;
        
        // 使用printf格式化输出
        System.out.printf("姓名:%s\n", name);
        System.out.printf("年龄:%d\n", age);
        System.out.printf("薪资:%.2f\n", salary);
        
        // 格式化说明符
        System.out.printf("整数:%d\n", 100);           // 十进制整数
        System.out.printf("浮点数:%f\n", 3.14);        // 浮点数
        System.out.printf("浮点数(2位小数):%.2f\n", 3.14159);
        System.out.printf("字符串:%s\n", "Hello");     // 字符串
        System.out.printf("字符:%c\n", 'A');           // 字符
        System.out.printf("布尔值:%b\n", true);        // 布尔值
        
        // 对齐和宽度
        System.out.printf("右对齐:%10s\n", "Hello");   // 右对齐,宽度10
        System.out.printf("左对齐:%-10s\n", "Hello");  // 左对齐,宽度10
        System.out.printf("补零:%05d\n", 42);          // 补零,宽度5
        
        // 表格输出
        System.out.println("\n学生成绩表:");
        System.out.printf("%-10s%-10s%-10s\n", "姓名", "语文", "数学");
        System.out.printf("%-10s%-10d%-10d\n", "张三", 85, 90);
        System.out.printf("%-10s%-10d%-10d\n", "李四", 92, 88);
        System.out.printf("%-10s%-10d%-10d\n", "王五", 78, 95);
    }
}

12.4 随机数生成

Random类的使用:

import java.util.Random;

public class RandomDemo {
    public static void main(String[] args) {
        Random random = new Random();
        
        // 生成随机整数
        int randomInt = random.nextInt();
        System.out.println("随机整数:" + randomInt);
        
        // 生成0-99的随机整数
        int randomInt100 = random.nextInt(100);
        System.out.println("0-99的随机整数:" + randomInt100);
        
        // 生成1-100的随机整数
        int randomInt1to100 = random.nextInt(100) + 1;
        System.out.println("1-100的随机整数:" + randomInt1to100);
        
        // 生成随机浮点数(0.0-1.0)
        double randomDouble = random.nextDouble();
        System.out.println("随机浮点数:" + randomDouble);
        
        // 生成随机布尔值
        boolean randomBoolean = random.nextBoolean();
        System.out.println("随机布尔值:" + randomBoolean);
        
        // 实际应用:生成验证码
        String code = generateCode(6);
        System.out.println("验证码:" + code);
        
        // 实际应用:随机抽奖
        String[] prizes = {"一等奖", "二等奖", "三等奖", "谢谢参与"};
        int index = random.nextInt(prizes.length);
        System.out.println("抽奖结果:" + prizes[index]);
    }
    
    /**
     * 生成指定长度的随机验证码
     */
    public static String generateCode(int length) {
        Random random = new Random();
        StringBuilder code = new StringBuilder();
        String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        
        for (int i = 0; i < length; i++) {
            int index = random.nextInt(chars.length());
            code.append(chars.charAt(index));
        }
        
        return code.toString();
    }
}

12.5 Math类常用方法

数学运算:

public class MathDemo {
    public static void main(String[] args) {
        // 绝对值
        System.out.println("abs(-5) = " + Math.abs(-5));           // 5
        System.out.println("abs(-3.14) = " + Math.abs(-3.14));     // 3.14
        
        // 最大值和最小值
        System.out.println("max(10, 20) = " + Math.max(10, 20));   // 20
        System.out.println("min(10, 20) = " + Math.min(10, 20));   // 10
        
        // 幂运算
        System.out.println("pow(2, 3) = " + Math.pow(2, 3));       // 8.0
        System.out.println("pow(5, 2) = " + Math.pow(5, 2));       // 25.0
        
        // 平方根
        System.out.println("sqrt(16) = " + Math.sqrt(16));         // 4.0
        System.out.println("sqrt(2) = " + Math.sqrt(2));           // 1.414...
        
        // 向上取整
        System.out.println("ceil(3.1) = " + Math.ceil(3.1));       // 4.0
        System.out.println("ceil(3.9) = " + Math.ceil(3.9));       // 4.0
        
        // 向下取整
        System.out.println("floor(3.1) = " + Math.floor(3.1));     // 3.0
        System.out.println("floor(3.9) = " + Math.floor(3.9));     // 3.0
        
        // 四舍五入
        System.out.println("round(3.4) = " + Math.round(3.4));     // 3
        System.out.println("round(3.5) = " + Math.round(3.5));     // 4
        
        // 随机数(0.0-1.0)
        System.out.println("random() = " + Math.random());
        
        // 常量
        System.out.println("PI = " + Math.PI);                     // 3.141592653589793
        System.out.println("E = " + Math.E);                       // 2.718281828459045
        
        // 实际应用:计算圆的面积和周长
        double radius = 5.0;
        double area = Math.PI * Math.pow(radius, 2);
        double circumference = 2 * Math.PI * radius;
        System.out.printf("\n半径为%.1f的圆:\n", radius);
        System.out.printf("面积:%.2f\n", area);
        System.out.printf("周长:%.2f\n", circumference);
        
        // 实际应用:计算两点之间的距离
        double x1 = 0, y1 = 0;
        double x2 = 3, y2 = 4;
        double distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
        System.out.printf("\n点(%.0f,%.0f)到点(%.0f,%.0f)的距离:%.2f\n", 
                         x1, y1, x2, y2, distance);
    }
}

12.6 日期和时间基础

Date类的使用:

import java.util.Date;
import java.text.SimpleDateFormat;

public class DateDemo {
    public static void main(String[] args) {
        // 创建Date对象(当前时间)
        Date now = new Date();
        System.out.println("当前时间:" + now);
        
        // 获取时间戳(毫秒)
        long timestamp = now.getTime();
        System.out.println("时间戳:" + timestamp);
        
        // 从时间戳创建Date对象
        Date date = new Date(timestamp);
        System.out.println("从时间戳创建:" + date);
        
        // 格式化日期
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String formatted1 = sdf1.format(now);
        System.out.println("格式化1:" + formatted1);
        
        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
        String formatted2 = sdf2.format(now);
        System.out.println("格式化2:" + formatted2);
        
        SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy/MM/dd");
        String formatted3 = sdf3.format(now);
        System.out.println("格式化3:" + formatted3);
        
        // 解析字符串为Date
        try {
            String dateStr = "2024-01-01 12:00:00";
            Date parsedDate = sdf1.parse(dateStr);
            System.out.println("解析字符串:" + parsedDate);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        // 比较日期
        Date date1 = new Date();
        Date date2 = new Date(date1.getTime() + 1000);  // 晚1秒
        
        System.out.println("\ndate1.before(date2): " + date1.before(date2));  // true
        System.out.println("date1.after(date2): " + date1.after(date2));      // false
        System.out.println("date1.equals(date2): " + date1.equals(date2));    // false
    }
}

12.7 包装类

基本类型的包装类:

public class WrapperDemo {
    public static void main(String[] args) {
        // 基本类型 -> 包装类(装箱)
        int i = 100;
        Integer obj1 = Integer.valueOf(i);      // 手动装箱
        Integer obj2 = i;                       // 自动装箱(JDK 5+)
        
        // 包装类 -> 基本类型(拆箱)
        Integer obj3 = 200;
        int j = obj3.intValue();                // 手动拆箱
        int k = obj3;                           // 自动拆箱(JDK 5+)
        
        System.out.println("装箱:" + obj1);
        System.out.println("拆箱:" + j);
        
        // 字符串 -> 基本类型
        String str1 = "123";
        int num1 = Integer.parseInt(str1);
        double num2 = Double.parseDouble("3.14");
        boolean flag = Boolean.parseBoolean("true");
        
        System.out.println("\n字符串转基本类型:");
        System.out.println("int: " + num1);
        System.out.println("double: " + num2);
        System.out.println("boolean: " + flag);
        
        // 基本类型 -> 字符串
        int num3 = 456;
        String str2 = String.valueOf(num3);
        String str3 = Integer.toString(num3);
        String str4 = num3 + "";
        
        System.out.println("\n基本类型转字符串:");
        System.out.println("方式1:" + str2);
        System.out.println("方式2:" + str3);
        System.out.println("方式3:" + str4);
        
        // 包装类的常用方法
        System.out.println("\n包装类常用方法:");
        System.out.println("Integer.MAX_VALUE: " + Integer.MAX_VALUE);
        System.out.println("Integer.MIN_VALUE: " + Integer.MIN_VALUE);
        System.out.println("Double.MAX_VALUE: " + Double.MAX_VALUE);
        System.out.println("Double.MIN_VALUE: " + Double.MIN_VALUE);
        
        // 进制转换
        int decimal = 255;
        String binary = Integer.toBinaryString(decimal);
        String octal = Integer.toOctalString(decimal);
        String hex = Integer.toHexString(decimal);
        
        System.out.println("\n进制转换:");
        System.out.println("十进制:" + decimal);
        System.out.println("二进制:" + binary);
        System.out.println("八进制:" + octal);
        System.out.println("十六进制:" + hex);
        
        // 从其他进制转换为十进制
        int fromBinary = Integer.parseInt("11111111", 2);
        int fromOctal = Integer.parseInt("377", 8);
        int fromHex = Integer.parseInt("FF", 16);
        
        System.out.println("\n转换为十进制:");
        System.out.println("二进制11111111:" + fromBinary);
        System.out.println("八进制377:" + fromOctal);
        System.out.println("十六进制FF:" + fromHex);
    }
}

12.3 位运算详解

位运算符:

运算符 说明 示例
& 按位与 5 & 3 = 1
| 按位或 5 | 3 = 7
^ 按位异或 5 ^ 3 = 6
~ 按位取反 ~5 = -6
<< 左移 5 << 1 = 10
>> 右移 5 >> 1 = 2
>>> 无符号右移 -5 >>> 1 = 2147483645

代码示例:位运算应用

public class BitOperations {
    public static void main(String[] args) {
        // 1. 判断奇偶性
        int num = 15;
        if ((num & 1) == 0) {
            System.out.println(num + "是偶数");
        } else {
            System.out.println(num + "是奇数");
        }
        
        // 2. 交换两个数(不使用临时变量)
        int a = 5, b = 10;
        System.out.println("交换前:a=" + a + ", b=" + b);
        a = a ^ b;
        b = a ^ b;
        a = a ^ b;
        System.out.println("交换后:a=" + a + ", b=" + b);
        
        // 3. 快速计算2的幂次
        int power = 1 << 10;  // 2^10 = 1024
        System.out.println("2的10次方:" + power);
        
        // 4. 判断是否为2的幂次
        int n = 16;
        boolean isPowerOfTwo = (n > 0) && ((n & (n - 1)) == 0);
        System.out.println(n + "是2的幂次:" + isPowerOfTwo);
        
        // 5. 统计二进制中1的个数
        int count = countOnes(15);  // 15 = 1111
        System.out.println("15的二进制中1的个数:" + count);
    }
    
    /**
     * 统计二进制中1的个数
     */
    public static int countOnes(int n) {
        int count = 0;
        while (n != 0) {
            n = n & (n - 1);  // 每次消除最右边的1
            count++;
        }
        return count;
    }
}

12.4 递归详解

什么是递归?

  • 方法调用自己的编程技巧
  • 必须有终止条件(基准情况)
  • 必须向终止条件靠近

递归的三要素:

  1. 明确递归函数的功能
  2. 找到递归终止条件
  3. 找出递归关系

代码示例1:阶乘

public class RecursionDemo1 {
    public static void main(String[] args) {
        int n = 5;
        int result = factorial(n);
        System.out.println(n + "的阶乘:" + result);
    }
    
    /**
     * 计算阶乘
     * n! = n * (n-1)!
     * 0! = 1
     */
    public static int factorial(int n) {
        // 终止条件
        if (n == 0 || n == 1) {
            return 1;
        }
        // 递归关系
        return n * factorial(n - 1);
    }
}

代码示例2:斐波那契数列

public class RecursionDemo2 {
    public static void main(String[] args) {
        // 打印前10项斐波那契数列
        System.out.println("斐波那契数列前10项:");
        for (int i = 0; i < 10; i++) {
            System.out.print(fibonacci(i) + " ");
        }
    }
    
    /**
     * 斐波那契数列
     * F(0) = 0, F(1) = 1
     * F(n) = F(n-1) + F(n-2)
     */
    public static int fibonacci(int n) {
        // 终止条件
        if (n == 0) return 0;
        if (n == 1) return 1;
        // 递归关系
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
}

代码示例3:汉诺塔问题

public class RecursionDemo3 {
    public static void main(String[] args) {
        int n = 3;  // 3个盘子
        System.out.println("移动" + n + "个盘子的步骤:");
        hanoi(n, 'A', 'B', 'C');
    }
    
    /**
     * 汉诺塔问题
     * @param n 盘子数量
     * @param from 起始柱子
     * @param auxiliary 辅助柱子
     * @param to 目标柱子
     */
    public static void hanoi(int n, char from, char auxiliary, char to) {
        if (n == 1) {
            // 只有一个盘子,直接移动
            System.out.println("移动盘子1从 " + from + " 到 " + to);
            return;
        }
        
        // 1. 将n-1个盘子从from移动到auxiliary(借助to)
        hanoi(n - 1, from, to, auxiliary);
        
        // 2. 将第n个盘子从from移动到to
        System.out.println("移动盘子" + n + "从 " + from + " 到 " + to);
        
        // 3. 将n-1个盘子从auxiliary移动到to(借助from)
        hanoi(n - 1, auxiliary, from, to);
    }
}

代码示例4:二分查找(递归实现)

public class RecursionDemo4 {
    public static void main(String[] args) {
        int[] arr = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
        int target = 13;
        
        int index = binarySearch(arr, target, 0, arr.length - 1);
        
        if (index != -1) {
            System.out.println("找到了,索引为:" + index);
        } else {
            System.out.println("没找到");
        }
    }
    
    /**
     * 二分查找(递归实现)
     */
    public static int binarySearch(int[] arr, int target, int left, int right) {
        // 终止条件
        if (left > right) {
            return -1;
        }
        
        int mid = left + (right - left) / 2;
        
        if (arr[mid] == target) {
            return mid;
        } else if (arr[mid] < target) {
            // 在右半部分查找
            return binarySearch(arr, target, mid + 1, right);
        } else {
            // 在左半部分查找
            return binarySearch(arr, target, left, mid - 1);
        }
    }
}

递归 vs 循环:

特性 递归 循环
代码简洁性 简洁优雅 相对复杂
性能 较慢(函数调用开销) 较快
内存使用 较多(调用栈) 较少
适用场景 树、图、分治问题 简单重复操作

12.5 方法重载详解

什么是方法重载?

  • 同一个类中,方法名相同,参数列表不同
  • 参数列表不同:参数个数、类型、顺序不同
  • 返回值类型不影响重载

代码示例:方法重载

public class MethodOverloading {
    public static void main(String[] args) {
        Calculator calc = new Calculator();
        
        // 调用不同的add方法
        System.out.println("两个int相加:" + calc.add(5, 3));
        System.out.println("三个int相加:" + calc.add(5, 3, 2));
        System.out.println("两个double相加:" + calc.add(5.5, 3.3));
        System.out.println("int和double相加:" + calc.add(5, 3.3));
    }
}

class Calculator {
    // 两个int参数
    public int add(int a, int b) {
        System.out.println("调用add(int, int)");
        return a + b;
    }
    
    // 三个int参数
    public int add(int a, int b, int c) {
        System.out.println("调用add(int, int, int)");
        return a + b + c;
    }
    
    // 两个double参数
    public double add(double a, double b) {
        System.out.println("调用add(double, double)");
        return a + b;
    }
    
    // int和double参数
    public double add(int a, double b) {
        System.out.println("调用add(int, double)");
        return a + b;
    }
    
    // double和int参数(参数顺序不同)
    public double add(double a, int b) {
        System.out.println("调用add(double, int)");
        return a + b;
    }
}

12.6 可变参数详解

什么是可变参数?

  • 允许方法接受不定数量的参数
  • 使用…表示
  • 本质是数组

代码示例:可变参数

public class VarargsDemo {
    public static void main(String[] args) {
        // 可以传入任意数量的参数
        System.out.println("和:" + sum(1, 2, 3));
        System.out.println("和:" + sum(1, 2, 3, 4, 5));
        System.out.println("和:" + sum());
        
        // 可变参数与普通参数混用
        printInfo("张三", 25, "北京", "上海", "深圳");
    }
    
    /**
     * 计算任意个数的和
     */
    public static int sum(int... numbers) {
        int total = 0;
        for (int num : numbers) {
            total += num;
        }
        return total;
    }
    
    /**
     * 可变参数与普通参数混用
     * 注意:可变参数必须放在最后
     */
    public static void printInfo(String name, int age, String... cities) {
        System.out.println("姓名:" + name);
        System.out.println("年龄:" + age);
        System.out.println("去过的城市:");
        for (String city : cities) {
            System.out.println("  - " + city);
        }
    }
}

12.7 Scanner输入详解

Scanner类的使用:

import java.util.Scanner;

public class ScannerDemo {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 1. 读取整数
        System.out.print("请输入一个整数:");
        int num = scanner.nextInt();
        System.out.println("你输入的整数是:" + num);
        
        // 2. 读取浮点数
        System.out.print("请输入一个小数:");
        double d = scanner.nextDouble();
        System.out.println("你输入的小数是:" + d);
        
        // 3. 读取字符串(不包含空格)
        System.out.print("请输入一个单词:");
        String word = scanner.next();
        System.out.println("你输入的单词是:" + word);
        
        // 清空缓冲区
        scanner.nextLine();
        
        // 4. 读取一行字符串(包含空格)
        System.out.print("请输入一句话:");
        String line = scanner.nextLine();
        System.out.println("你输入的话是:" + line);
        
        // 5. 读取布尔值
        System.out.print("请输入true或false:");
        boolean bool = scanner.nextBoolean();
        System.out.println("你输入的布尔值是:" + bool);
        
        // 关闭Scanner
        scanner.close();
    }
}

Scanner常见问题:

import java.util.Scanner;

public class ScannerPitfalls {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 问题1:nextInt()后使用nextLine()
        System.out.print("请输入年龄:");
        int age = scanner.nextInt();
        
        // 这里会跳过,因为nextInt()不会读取换行符
        // System.out.print("请输入姓名:");
        // String name = scanner.nextLine();  // 会读取到空字符串
        
        // 解决方法:先清空缓冲区
        scanner.nextLine();  // 读取并丢弃换行符
        System.out.print("请输入姓名:");
        String name = scanner.nextLine();
        
        System.out.println("年龄:" + age);
        System.out.println("姓名:" + name);
        
        // 问题2:输入类型不匹配
        System.out.print("请输入一个数字:");
        try {
            int num = scanner.nextInt();
            System.out.println("你输入的数字是:" + num);
        } catch (java.util.InputMismatchException e) {
            System.out.println("输入格式错误,请输入数字!");
            scanner.next();  // 清除错误输入
        }
        
        scanner.close();
    }
}

12.8 Random随机数详解

Random类的使用:

import java.util.Random;

public class RandomDemo {
    public static void main(String[] args) {
        Random random = new Random();
        
        // 1. 生成随机整数
        int randomInt = random.nextInt();
        System.out.println("随机整数:" + randomInt);
        
        // 2. 生成指定范围的随机整数 [0, n)
        int randomInRange = random.nextInt(100);  // 0-99
        System.out.println("0-99的随机数:" + randomInRange);
        
        // 3. 生成指定范围的随机整数 [min, max]
        int min = 10, max = 20;
        int randomBetween = random.nextInt(max - min + 1) + min;
        System.out.println("10-20的随机数:" + randomBetween);
        
        // 4. 生成随机浮点数 [0.0, 1.0)
        double randomDouble = random.nextDouble();
        System.out.println("随机小数:" + randomDouble);
        
        // 5. 生成随机布尔值
        boolean randomBoolean = random.nextBoolean();
        System.out.println("随机布尔值:" + randomBoolean);
        
        // 6. 使用种子生成可重复的随机数
        Random seededRandom = new Random(12345);
        System.out.println("使用种子的随机数:" + seededRandom.nextInt(100));
    }
}

实战案例:随机点名系统

import java.util.Random;

public class RandomNamePicker {
    public static void main(String[] args) {
        String[] students = {"张三", "李四", "王五", "赵六", "钱七"};
        Random random = new Random();
        
        System.out.println("开始随机点名...");
        
        // 随机选择一个学生
        int index = random.nextInt(students.length);
        String selectedStudent = students[index];
        
        System.out.println("被点到的学生是:" + selectedStudent);
        
        // 随机选择多个不重复的学生
        System.out.println("\n随机选择3个学生:");
        boolean[] selected = new boolean[students.length];
        int count = 0;
        
        while (count < 3) {
            int idx = random.nextInt(students.length);
            if (!selected[idx]) {
                System.out.println((count + 1) + ". " + students[idx]);
                selected[idx] = true;
                count++;
            }
        }
    }
}

实战案例:生成验证码

import java.util.Random;

public class VerificationCodeGenerator {
    public static void main(String[] args) {
        // 生成6位数字验证码
        String code1 = generateNumericCode(6);
        System.out.println("数字验证码:" + code1);
        
        // 生成6位字母验证码
        String code2 = generateAlphaCode(6);
        System.out.println("字母验证码:" + code2);
        
        // 生成6位混合验证码
        String code3 = generateMixedCode(6);
        System.out.println("混合验证码:" + code3);
    }
    
    /**
     * 生成数字验证码
     */
    public static String generateNumericCode(int length) {
        Random random = new Random();
        StringBuilder code = new StringBuilder();
        
        for (int i = 0; i < length; i++) {
            code.append(random.nextInt(10));
        }
        
        return code.toString();
    }
    
    /**
     * 生成字母验证码
     */
    public static String generateAlphaCode(int length) {
        Random random = new Random();
        StringBuilder code = new StringBuilder();
        
        for (int i = 0; i < length; i++) {
            // 随机生成大写或小写字母
            if (random.nextBoolean()) {
                // 大写字母 A-Z (65-90)
                code.append((char) (random.nextInt(26) + 'A'));
            } else {
                // 小写字母 a-z (97-122)
                code.append((char) (random.nextInt(26) + 'a'));
            }
        }
        
        return code.toString();
    }
    
    /**
     * 生成混合验证码(数字+字母)
     */
    public static String generateMixedCode(int length) {
        Random random = new Random();
        StringBuilder code = new StringBuilder();
        String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        
        for (int i = 0; i < length; i++) {
            int index = random.nextInt(chars.length());
            code.append(chars.charAt(index));
        }
        
        return code.toString();
    }
}

12.9 Math数学工具类详解

Math类常用方法:

public class MathDemo {
    public static void main(String[] args) {
        // 1. 绝对值
        System.out.println("abs(-5) = " + Math.abs(-5));  // 5
        
        // 2. 最大值和最小值
        System.out.println("max(10, 20) = " + Math.max(10, 20));  // 20
        System.out.println("min(10, 20) = " + Math.min(10, 20));  // 10
        
        // 3. 幂运算
        System.out.println("pow(2, 3) = " + Math.pow(2, 3));  // 8.0
        
        // 4. 平方根
        System.out.println("sqrt(16) = " + Math.sqrt(16));  // 4.0
        
        // 5. 向上取整
        System.out.println("ceil(3.2) = " + Math.ceil(3.2));  // 4.0
        
        // 6. 向下取整
        System.out.println("floor(3.8) = " + Math.floor(3.8));  // 3.0
        
        // 7. 四舍五入
        System.out.println("round(3.5) = " + Math.round(3.5));  // 4
        System.out.println("round(3.4) = " + Math.round(3.4));  // 3
        
        // 8. 随机数 [0.0, 1.0)
        System.out.println("random() = " + Math.random());
        
        // 9. 常量
        System.out.println("PI = " + Math.PI);  // 3.141592653589793
        System.out.println("E = " + Math.E);    // 2.718281828459045
        
        // 10. 三角函数
        System.out.println("sin(30°) = " + Math.sin(Math.toRadians(30)));
        System.out.println("cos(60°) = " + Math.cos(Math.toRadians(60)));
        System.out.println("tan(45°) = " + Math.tan(Math.toRadians(45)));
    }
}

实战案例:计算圆的面积和周长

public class CircleCalculator {
    public static void main(String[] args) {
        double radius = 5.0;
        
        // 计算面积
        double area = Math.PI * Math.pow(radius, 2);
        System.out.printf("半径为%.2f的圆的面积:%.2f\n", radius, area);
        
        // 计算周长
        double circumference = 2 * Math.PI * radius;
        System.out.printf("半径为%.2f的圆的周长:%.2f\n", radius, circumference);
    }
}

实战案例:计算两点之间的距离

public class DistanceCalculator {
    public static void main(String[] args) {
        // 点A(1, 2),点B(4, 6)
        double x1 = 1, y1 = 2;
        double x2 = 4, y2 = 6;
        
        // 使用勾股定理计算距离
        double distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
        
        System.out.printf("点A(%.1f, %.1f)到点B(%.1f, %.1f)的距离:%.2f\n", 
                         x1, y1, x2, y2, distance);
    }
}

12.10 Arrays工具类详解

Arrays类常用方法:

import java.util.Arrays;

public class ArraysDemo {
    public static void main(String[] args) {
        int[] arr = {5, 2, 8, 1, 9};
        
        // 1. 排序
        Arrays.sort(arr);
        System.out.println("排序后:" + Arrays.toString(arr));
        
        // 2. 二分查找(数组必须有序)
        int index = Arrays.binarySearch(arr, 8);
        System.out.println("8的索引:" + index);
        
        // 3. 数组转字符串
        String str = Arrays.toString(arr);
        System.out.println("数组转字符串:" + str);
        
        // 4. 数组复制
        int[] copy = Arrays.copyOf(arr, arr.length);
        System.out.println("复制的数组:" + Arrays.toString(copy));
        
        // 5. 部分复制
        int[] partialCopy = Arrays.copyOfRange(arr, 1, 4);
        System.out.println("部分复制:" + Arrays.toString(partialCopy));
        
        // 6. 数组填充
        int[] filled = new int[5];
        Arrays.fill(filled, 10);
        System.out.println("填充后:" + Arrays.toString(filled));
        
        // 7. 数组比较
        int[] arr2 = {1, 2, 5, 8, 9};
        boolean equals = Arrays.equals(arr, arr2);
        System.out.println("两个数组相等:" + equals);
        
        // 8. 多维数组转字符串
        int[][] matrix = {{1, 2}, {3, 4}};
        System.out.println("二维数组:" + Arrays.deepToString(matrix));
    }
}

12.11 格式化输出详解

printf格式化输出:

public class PrintfDemo {
    public static void main(String[] args) {
        // 1. 整数格式化
        int num = 123;
        System.out.printf("整数:%d\n", num);
        System.out.printf("5位整数(右对齐):%5d\n", num);
        System.out.printf("5位整数(左对齐):%-5d\n", num);
        System.out.printf("5位整数(补0):%05d\n", num);
        
        // 2. 浮点数格式化
        double pi = 3.141592653;
        System.out.printf("浮点数:%f\n", pi);
        System.out.printf("保留2位小数:%.2f\n", pi);
        System.out.printf("科学计数法:%e\n", pi);
        
        // 3. 字符串格式化
        String name = "张三";
        System.out.printf("字符串:%s\n", name);
        System.out.printf("10位字符串(右对齐):%10s\n", name);
        System.out.printf("10位字符串(左对齐):%-10s\n", name);
        
        // 4. 字符格式化
        char ch = 'A';
        System.out.printf("字符:%c\n", ch);
        
        // 5. 布尔值格式化
        boolean flag = true;
        System.out.printf("布尔值:%b\n", flag);
        
        // 6. 百分号
        double rate = 0.85;
        System.out.printf("百分比:%.2f%%\n", rate * 100);
        
        // 7. 综合示例:格式化表格
        System.out.println("\n学生成绩表:");
        System.out.printf("%-10s %5s %8s\n", "姓名", "年龄", "成绩");
        System.out.printf("%-10s %5d %8.2f\n", "张三", 20, 85.5);
        System.out.printf("%-10s %5d %8.2f\n", "李四", 21, 92.3);
        System.out.printf("%-10s %5d %8.2f\n", "王五", 19, 78.9);
    }
}

String.format格式化:

public class StringFormatDemo {
    public static void main(String[] args) {
        // 使用String.format创建格式化字符串
        String name = "张三";
        int age = 25;
        double score = 85.5;
        
        String info = String.format("姓名:%s,年龄:%d,成绩:%.2f", name, age, score);
        System.out.println(info);
        
        // 格式化日期
        int year = 2024, month = 1, day = 15;
        String date = String.format("%04d-%02d-%02d", year, month, day);
        System.out.println("日期:" + date);
        
        // 格式化金额
        double amount = 12345.678;
        String money = String.format("金额:¥%,.2f", amount);
        System.out.println(money);
    }
}

12.12 常见算法模板

1. 冒泡排序模板

public class BubbleSortTemplate {
    /**
     * 冒泡排序模板
     * 时间复杂度:O(n²)
     * 空间复杂度:O(1)
     * 稳定性:稳定
     */
    public static void bubbleSort(int[] arr) {
        int n = arr.length;
        for (int i = 0; i < n - 1; i++) {
            boolean swapped = false;
            for (int j = 0; j < n - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    // 交换
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    swapped = true;
                }
            }
            if (!swapped) break;  // 优化:如果没有交换,说明已经有序
        }
    }
}

2. 选择排序模板

public class SelectionSortTemplate {
    /**
     * 选择排序模板
     * 时间复杂度:O(n²)
     * 空间复杂度:O(1)
     * 稳定性:不稳定
     */
    public static void selectionSort(int[] arr) {
        int n = arr.length;
        for (int i = 0; i < n - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j < n; j++) {
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            if (minIndex != i) {
                int temp = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = temp;
            }
        }
    }
}

3. 插入排序模板

public class InsertionSortTemplate {
    /**
     * 插入排序模板
     * 时间复杂度:O(n²)
     * 空间复杂度:O(1)
     * 稳定性:稳定
     */
    public static void insertionSort(int[] arr) {
        int n = arr.length;
        for (int i = 1; i < n; i++) {
            int key = arr[i];
            int j = i - 1;
            while (j >= 0 && arr[j] > key) {
                arr[j + 1] = arr[j];
                j--;
            }
            arr[j + 1] = key;
        }
    }
}

4. 二分查找模板

public class BinarySearchTemplate {
    /**
     * 二分查找模板
     * 时间复杂度:O(log n)
     * 空间复杂度:O(1)
     * 前提:数组必须有序
     */
    public static int binarySearch(int[] arr, int target) {
        int left = 0, right = arr.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (arr[mid] == target) {
                return mid;
            } else if (arr[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return -1;
    }
}

5. 双指针模板

public class TwoPointersTemplate {
    /**
     * 双指针模板:数组反转
     */
    public static void reverse(int[] arr) {
        int left = 0, right = arr.length - 1;
        while (left < right) {
            int temp = arr[left];
            arr[left] = arr[right];
            arr[right] = temp;
            left++;
            right--;
        }
    }
    
    /**
     * 双指针模板:删除重复元素
     */
    public static int removeDuplicates(int[] arr) {
        if (arr.length == 0) return 0;
        int slow = 0;
        for (int fast = 1; fast < arr.length; fast++) {
            if (arr[fast] != arr[slow]) {
                slow++;
                arr[slow] = arr[fast];
            }
        }
        return slow + 1;
    }
}
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐