01-Java开发环境与基础语法之下篇
八、综合练习题
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是编译型和解释型的混合语言
- 编译阶段:Java源代码(.java)被javac编译成字节码(.class)
- 解释阶段:JVM解释执行字节码,或通过JIT编译器编译成机器码执行
Q3:为什么Java是跨平台的?
A:
- Java源代码编译成平台无关的字节码
- 不同操作系统有不同的JVM实现
- JVM负责将字节码转换为特定平台的机器码
- 实现了"一次编写,到处运行"(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:
- 存储相同类型的数据
- 长度固定,创建后不能改变
- 内存连续,通过索引快速访问
- 索引从0开始
Q11:如何复制数组?
A:有多种方式
- 循环复制
- System.arraycopy()
- Arrays.copyOf()
- clone()
注意:直接赋值不是复制,而是引用
Q12:数组越界会发生什么?
A:抛出ArrayIndexOutOfBoundsException异常
预防方法:
- 访问前检查索引范围:index >= 0 && index < arr.length
- 使用增强for循环遍历
- 使用Arrays工具类的方法
9.4 字符串
Q13:String、StringBuilder、StringBuffer的区别?
A:
| 特性 | String | StringBuilder | StringBuffer |
|---|---|---|---|
| 可变性 | 不可变 | 可变 | 可变 |
| 线程安全 | 安全 | 不安全 | 安全 |
| 性能 | 慢 | 快 | 较快 |
| 使用场景 | 字符串不变 | 单线程字符串拼接 | 多线程字符串拼接 |
Q14:为什么String是不可变的?
A:
- String内部使用final char[]存储数据
- 没有提供修改字符数组的方法
- 所有"修改"操作都会创建新对象
好处:
- 线程安全
- 可以缓存hash值
- 可以使用字符串常量池
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:三种注释
- 单行注释:// 注释内容
- 多行注释:/* 注释内容 */
- 文档注释:/** 注释内容 */(可以生成API文档)
Q19:Java命名规范是什么?
A:
- 类名:大驼峰命名法(UserService)
- 方法名:小驼峰命名法(getUserName)
- 变量名:小驼峰命名法(userName)
- 常量名:全大写,下划线分隔(MAX_SIZE)
- 包名:全小写,点分隔(com.example.project)
Q20:如何提高代码的可读性?
A:
- 使用有意义的变量名和方法名
- 添加适当的注释
- 保持代码简洁,一个方法只做一件事
- 使用空行分隔逻辑块
- 遵循代码规范
- 避免过深的嵌套
- 使用常量代替魔法数字
十、学习检查清单
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源文件
javac HelloWorld.java
# 生成字节码文件
HelloWorld.class
- 类加载阶段
- 加载(Loading):读取.class文件
- 链接(Linking):验证、准备、解析
- 初始化(Initialization):执行静态代码块
- 执行阶段
- 解释执行:逐行解释字节码
- 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:阶乘
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;
}
}
更多推荐




所有评论(0)