第一部分:API文档与String类
1. API的概念与使用
Q: 什么是API?如何学习使用API?
A: API(Application Programming Interface,应用程序编程接口)是别人已经写好的类,我们直接使用即可,无需自己编写。
学习方法:
- 查阅官方API文档(使用说明书)
- 使用AI工具辅助学习(现代推荐方式)
- 关注:所属包、构造器、常用方法
// 示例:使用Random API生成随机数
import java.util.Random;
public class Demo {
public static void main(String[] args) {
Random r = new Random(); // 创建Random对象
int number = r.nextInt(100); // 调用API方法生成0-99的随机数
System.out.println(number);
}
}
// 常用API包:
// java.lang - 基础类(String、Object、System),自动导入
// java.util - 工具类(集合、日期、Random)
// java.io - 输入输出(文件操作)
// java.time - 现代日期时间处理(JDK8+)
2. String类的创建方式
Q: String类有哪两种创建方式?有什么区别?
A: 两种方式:
- 直接赋值:
String s = "abc";→ 字符串常量池,相同内容只存一份 - new构造器:
String s = new String("abc");→ 堆内存,每次new都创建新对象
public class Demo01 {
public static void main(String[] args) {
// 方式一:直接赋值(推荐,节省内存)
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); // true,同一常量池对象
// 方式二:new构造器
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s3 == s4); // false,不同堆对象
System.out.println(s1 == s3); // false,常量池 vs 堆
// 其他构造器
String s5 = new String(); // 空字符串
String s6 = new String("hello"); // 传入字符串
String s7 = new String(new char[]{'a','b'}); // 字符数组
String s8 = new String(new byte[]{97,98}); // 字节数组(转ASCII)
System.out.println(s8); // "ab"
}
}
3. String常用方法
Q: String类有哪些常用方法?请分类说明。
A:
| 类别 | 方法 | 说明 |
|---|---|---|
| 获取信息 | length() |
字符串长度 |
charAt(index) |
获取索引处字符 | |
toCharArray() |
转字符数组 | |
| 比较 | equals() |
内容相等比较 |
equalsIgnoreCase() |
忽略大小写比较 | |
| 截取 | substring(begin, end) |
截取[begin, end) |
substring(begin) |
截取到末尾 | |
| 替换 | replace(old, new) |
替换字符/字符串 |
| 判断 | contains(str) |
是否包含 |
startsWith(prefix) |
是否以某前缀开头 | |
| 分割 | split(regex) |
按正则分割 |
public class Demo02 {
public static void main(String[] args) {
String s1 = "hello 中国";
// 1. 获取信息
System.out.println(s1.length()); // 8(空格+中文各算1个)
System.out.println(s1.charAt(6)); // 中
char[] chars = s1.toCharArray(); // ['h','e','l','l','o',' ','中','国']
// 2. 比较
System.out.println(s1.equals("hello 中国")); // true
System.out.println(s1.equals("Hello 中国")); // false
System.out.println(s1.equalsIgnoreCase("Hello 中国")); // true
// 3. 截取(包前不包后)
System.out.println(s1.substring(6, 8)); // 中国(索引6到7)
System.out.println(s1.substring(6)); // 中国(从6到末尾)
// 4. 替换
System.out.println(s1.replace('l', '*')); // he**o 中国
System.out.println(s1.replace("hello", "hi")); // hi 中国
// 5. 判断
System.out.println(s1.contains("中国")); // true
System.out.println(s1.startsWith("he")); // true
System.out.println(s1.startsWith("el")); // false
// 6. 分割
String[] arr = s1.split(" "); // 按空格分割
System.out.println(Arrays.toString(arr)); // [hello, 中国]
}
}
4. String的不可变性
Q: 为什么说String是不可变字符串?有什么影响?
A: 不可变性:String对象创建后内容不能改变,每次"修改"都会创建新对象。
影响:频繁字符串拼接会产生大量临时对象,浪费内存。大量拼接时应使用 StringBuilder。
public class Demo {
public static void main(String[] args) {
String s = "hello";
// 看似修改,实际创建了新对象
s += " world"; // 创建新对象"hello world",原"hello"不变
s += "!"; // 又创建新对象
// 内存中现在有:"hello"、"hello world"、"hello world!"三个对象
// 高效拼接方式:StringBuilder(可变)
StringBuilder sb = new StringBuilder();
sb.append("hello");
sb.append(" world");
sb.append("!");
String result = sb.toString(); // "hello world!"
// 整个过程只创建一个StringBuilder对象,效率更高
}
}
5. 字符串案例:生成随机验证码
Q: 如何生成指定位数的随机验证码(包含数字、大小写字母)?
A: 思路:
- 定义包含所有可能字符的字符串
- 循环n次,每次随机获取一个字符拼接
- 返回拼接结果
import java.util.Random;
public class Demo04 {
public static void main(String[] args) {
String code4 = generateCode(4); // 生成4位验证码
String code6 = generateCode(6); // 生成6位验证码
System.out.println("4位验证码:" + code4);
System.out.println("6位验证码:" + code6);
}
/**
* 生成n位随机验证码
* @param n 验证码位数
* @return 验证码字符串
*/
private static String generateCode(int n) {
Random r = new Random();
// 1. 定义所有可能字符
String data = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
String code = ""; // 保存验证码
// 2. 循环n次,随机获取字符
for (int i = 0; i < n; i++) {
int index = r.nextInt(data.length()); // 0 ~ data.length()-1
char c = data.charAt(index); // 获取随机字符
code += c; // 拼接到验证码
}
// 3. 返回结果
return code;
}
}
第二部分:ArrayList集合
6. ArrayList的概念与创建
Q: 什么是ArrayList?与数组有什么区别?如何创建?
A: ArrayList是集合框架中的动态数组,大小可变,底层是数组自动扩容。
与数组区别:
- 数组:长度固定,初始化后不能改变
- ArrayList:长度可变,自动扩容
import java.util.ArrayList;
public class Demo01 {
public static void main(String[] args) {
// 创建ArrayList:使用泛型指定存储类型
ArrayList<String> list = new ArrayList<>(); // JDK7+ 钻石运算符
// 添加元素
list.add("我爱"); // 末尾添加
list.add("中国");
list.add("Java");
System.out.println(list); // [我爱, 中国, Java]
// 对比数组:数组长度固定
String[] arr = new String[3];
// arr[3] = "越界"; // ArrayIndexOutOfBoundsException
// ArrayList自动扩容
list.add("第四个"); // 自动扩容,无问题
list.add("第五个");
}
}
7. 泛型与包装类
Q: 什么是泛型?为什么基本类型不能直接用于泛型?如何解决?
A: 泛型:<E>中的E是类型参数,用于限定集合存储的数据类型,必须是引用类型。
包装类:基本类型对应的引用类型,用于泛型集合。
| 基本类型 | 包装类 |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
| boolean | Boolean |
public class Demo02 {
public static void main(String[] args) {
// ❌ 错误:泛型不能使用基本类型
// ArrayList<int> list = new ArrayList<int>(); // 编译错误!
// ✅ 正确:使用包装类
ArrayList<Integer> intList = new ArrayList<>();
intList.add(100); // 自动装箱:int → Integer
intList.add(200);
int num = intList.get(0); // 自动拆箱:Integer → int
ArrayList<Double> doubleList = new ArrayList<>();
doubleList.add(3.14);
doubleList.add(6.66);
// 其他包装类
ArrayList<Boolean> boolList = new ArrayList<>();
ArrayList<Character> charList = new ArrayList<>();
}
}
8. ArrayList常用方法
Q: ArrayList有哪些常用方法?
A:
| 方法 | 说明 |
|---|---|
add(E e) |
末尾添加元素 |
add(int index, E e) |
指定位置插入 |
get(int index) |
获取指定索引元素 |
size() |
返回元素个数 |
remove(int index) |
删除指定索引元素,返回被删元素 |
remove(Object o) |
删除指定对象,返回是否成功 |
set(int index, E e) |
修改指定索引元素,返回原元素 |
public class Demo03 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
// 添加
list.add("张益达"); // ["张益达"]
list.add("张伟");
list.add("张大炮"); // ["张益达", "张伟", "张大炮"]
list.add(1, "snake"); // 索引1插入 ["张益达", "snake", "张伟", "张大炮"]
System.out.println(list);
// 获取
String name = list.get(1); // "snake"
int size = list.size(); // 4
// 删除
String removed = list.remove(1); // 删除"snake",返回"snake"
boolean success = list.remove("张益达"); // true,删除成功
// 修改
String old = list.set(1, "张益达"); // "张伟"被替换,返回"张伟"
// 遍历(快捷键:list.fori 或 list.forr)
System.out.println("正序遍历:");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("倒序遍历:");
for (int i = list.size() - 1; i >= 0; i--) {
System.out.println(list.get(i));
}
}
}
9. ArrayList存储自定义对象
Q: 如何在ArrayList中存储自定义对象(如Student)?
A: 使用泛型指定自定义类型,结合Lombok简化代码。
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Data // 生成getter、setter、toString、equals、hashCode
@NoArgsConstructor // 无参构造
@AllArgsConstructor // 全参构造
class Student {
private String name;
private int age;
}
public class Demo023 {
public static void main(String[] args) {
// 创建学生集合
List<Student> studentList = new ArrayList<>(); // 多态:接口引用指向实现类
// 添加学生对象
studentList.add(new Student("播仔", 20));
studentList.add(new Student("播妞", 18));
studentList.add(new Student("黑金", 22));
// 遍历
for (int i = 0; i < studentList.size(); i++) {
Student student = studentList.get(i);
System.out.println(student); // 自动调用toString()
}
// 或使用增强for
for (Student s : studentList) {
System.out.println(s.getName() + "," + s.getAge() + "岁");
}
}
}
第三部分:Lambda表达式
10. Lambda表达式的概念与语法
Q: 什么是Lambda表达式?有什么作用?
A: Lambda表达式:JDK8新增的语法,用于简化函数式接口的匿名内部类写法。
函数式接口:有且仅有一个抽象方法的接口(可用 @FunctionalInterface注解检查)。
语法:(形参列表) -> { 方法体代码 }
import java.util.Arrays;
import java.util.Comparator;
public class Test {
public static void main(String[] args) {
Integer[] arr = {10, 88, 52, 21, 76, 92, 28, 55, 39, 82};
// 匿名内部类写法(繁琐)
Arrays.sort(arr, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1; // 降序
}
});
// Lambda表达式写法(简洁)
Arrays.sort(arr, (Integer o1, Integer o2) -> {
return o2 - o1;
});
System.out.println(Arrays.toString(arr)); // [92, 88, 82, 76, 55, 52, 39, 28, 21, 10]
}
}
11. Lambda表达式的省略规则
Q: Lambda表达式有哪些省略规则?
A: 省略规则:
- 参数类型可省略
- 只有一个参数时,括号
()可省略 - 方法体只有一句代码时,
{}和return可一起省略
public class Demo {
public static void main(String[] args) {
Integer[] arr = {10, 88, 52, 21, 76};
// 完整写法
Arrays.sort(arr, (Integer o1, Integer o2) -> {
return o2 - o1;
});
// 省略1:参数类型
Arrays.sort(arr, (o1, o2) -> {
return o2 - o1;
});
// 省略2:方法体只有一句,省略{}和return
Arrays.sort(arr, (o1, o2) -> o2 - o1);
// 只有一个参数的例子
ArrayList<Integer> list = new ArrayList<>();
list.add(10); list.add(20); list.add(30);
// 完整
list.forEach((Integer num) -> {
System.out.println(num);
});
// 省略:参数类型 + 只有一个参数省略() + 方法体省略{}
list.forEach(num -> System.out.println(num));
// 方法引用进一步简化(下一节)
list.forEach(System.out::println);
}
}
12. Lambda表达式案例:学生排序
Q: 如何使用Lambda表达式对学生进行多条件排序(年龄降序,年龄相同则身高降序)?
A: 思路:在Comparator中先比较主要条件,相等时再比较次要条件。
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Arrays;
@Data
@NoArgsConstructor
@AllArgsConstructor
class Student {
private String name;
private int age;
private double height;
}
public class Demo03 {
public static void main(String[] args) {
Student[] students = {
new Student("古力娜扎", 26, 166.6),
new Student("迪丽热巴", 26, 168.2),
new Student("马尔扎哈", 28, 188.5)
};
// Lambda排序:先按年龄降序,年龄相同按身高降序
Arrays.sort(students, (s1, s2) -> {
// 1. 先按年龄降序
int result = s2.getAge() - s1.getAge(); // 后减前 = 降序
// 2. 年龄相同(result == 0),按身高降序
if (result == 0) {
// 不能直接用减法,double转int会丢失精度
// return (int)(s2.getHeight() - s1.getHeight()); // ❌ 危险
// 推荐:使用Double.compare
result = Double.compare(s2.getHeight(), s1.getHeight());
}
return result;
});
// 打印结果
for (Student s : students) {
System.out.println(s);
}
// 输出顺序:马尔扎哈(28岁) → 迪丽热巴(26岁,168.2) → 古力娜扎(26岁,166.6)
}
}
第四部分:方法引用
13. 方法引用的概念与分类
Q: 什么是方法引用?有哪些类型?
A: 方法引用:利用已存在的方法,进一步简化Lambda表达式。语法:类名/对象名::方法名
分类:
- 静态方法引用:
类名::静态方法 - 实例方法引用:
对象名::实例方法 - 特定类型实例方法引用:
类名::实例方法
// 前提:Lambda表达式中只是调用一个已存在的方法,且参数返回值匹配
// 原Lambda
Arrays.sort(arr, (o1, o2) -> Double.compare(o1, o2));
// 静态方法引用简化
Arrays.sort(arr, Double::compare); // 类名::静态方法
14. 静态方法引用
Q: 如何使用静态方法引用?适用场景是什么?
A: 语法:类名::静态方法
适用场景:Lambda中调用静态方法,且参数返回值匹配。
public class Student {
private String name;
private int age;
private double score;
// 准备静态方法:年龄升序比较
public static int compareAgeStaticASC(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
}
public class Demo041 {
public static void main(String[] args) {
Student[] students = {
new Student("小王", 12, 99),
new Student("小张", 24, 100),
new Student("小李", 18, 66)
};
// Lambda写法
// Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge());
// 静态方法引用:类名::静态方法名
Arrays.sort(students, Student::compareAgeStaticASC);
// 打印
for (Student s : students) {
System.out.println(s);
}
// 按年龄升序:小王(12) → 小李(18) → 小张(24)
}
}
15. 实例方法引用
Q: 如何使用实例方法引用?与静态方法引用有什么区别?
A: 语法:对象名::实例方法
区别:调用的是对象的实例方法,需要先创建对象。
public class Student {
private String name;
private int age;
private double score;
// 实例方法:年龄升序
public int compareAgeASC(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
// 实例方法:年龄降序
public int compareAgeDESC(Student o1, Student o2) {
return o2.getAge() - o1.getAge();
}
}
public class Demo042 {
public static void main(String[] args) {
Student[] students = {
new Student("小王", 12, 99),
new Student("小张", 24, 100),
new Student("小李", 18, 66)
};
// 创建对象
Student student = new Student();
// 实例方法引用:对象名::实例方法名
Arrays.sort(students, student::compareAgeASC); // 升序
System.out.println("升序:" + Arrays.toString(students));
Arrays.sort(students, student::compareAgeDESC); // 降序
System.out.println("降序:" + Arrays.toString(students));
}
}
16. 特定类型实例方法引用
Q: 什么是特定类型实例方法引用?与前两种有什么区别?
A: 语法:类名::实例方法
特点:Lambda的第一个参数作为实例方法的调用者,其他参数作为方法参数。
public class Student {
// 特定类型实例方法:this调用者 vs 参数
public int compareAgeASC2(Student o2) {
return this.getAge() - o2.getAge(); // this vs o2
}
public int compareAgeDESC2(Student o2) {
return o2.getAge() - this.getAge(); // o2 vs this
}
}
public class Demo043 {
public static void main(String[] args) {
Student[] students = {
new Student("小王", 12, 99),
new Student("小张", 24, 100),
new Student("小李", 18, 66)
};
// 特定类型实例方法引用:类名::实例方法名
// 规则:o1.compareAgeASC2(o2) → Student::compareAgeASC2
Arrays.sort(students, Student::compareAgeASC2);
// 对比:
// 静态方法引用: 类名::静态方法 Student::staticMethod
// 实例方法引用: 对象名::实例方法 obj::instanceMethod
// 特定类型实例引用: 类名::实例方法 Student::instanceMethod(第一个参数是调用者)
}
}
第五部分:综合项目实战(员工管理系统)
17. 项目架构设计
Q: 员工管理系统的整体架构如何设计?包含哪些核心模块?
A: 架构设计:
- 实体类:
User(用户)、Employee(员工) - 数据层:静态集合存储数据(模拟数据库)
- 业务层:登录验证、CRUD操作
- 表现层:控制台交互界面
// ========== 实体类 ==========
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String username;
private String password;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
private int id;
private String name;
private String gender;
private double salary;
private String deptName;
}
// ========== 主程序结构 ==========
public class EmployeeManagementSystem {
// 数据层:静态集合(模拟数据库)
private static ArrayList<User> userList = new ArrayList<>();
private static ArrayList<Employee> employeeList = new ArrayList<>();
private static Scanner sc = new Scanner(System.in);
// 静态代码块:初始化数据
static {
userList.add(new User("admin", "123456"));
userList.add(new User("itheima", "123456"));
employeeList.add(new Employee(1, "张三", "男", 5000, "技术部"));
employeeList.add(new Employee(2, "李四", "男", 6000, "销售部"));
}
public static void main(String[] args) {
loginUI(); // 启动登录界面
}
// 各功能模块方法...
}
18. 登录功能实现
Q: 如何实现用户登录功能?包含哪些步骤?
A: 实现步骤:
- 循环显示登录界面
- 接收用户名密码输入
- 调用验证方法
- 成功进入操作界面,失败提示重新输入
/**
* 登录界面方法
*/
private static void loginUI() {
while (true) {
System.out.println("----------欢迎来到员工管理系统登录界面----------");
System.out.print("请输入用户名:");
String username = sc.next();
System.out.print("请输入密码:");
String password = sc.next();
// 封装用户对象
User user = new User(username, password);
// 验证登录
boolean flag = checkUserNameAndPassword(user);
if (flag) {
System.out.println("登录成功!");
showOperationUI(); // 进入操作界面
return; // 结束登录循环
} else {
System.out.println("用户名或密码错误,请重新输入!");
}
}
}
/**
* 校验用户名与密码
*/
private static boolean checkUserNameAndPassword(User user) {
// 遍历用户列表比对
for (User u : userList) {
if (u.getUsername().equals(user.getUsername()) &&
u.getPassword().equals(user.getPassword())) {
return true; // 登录成功
}
}
return false; // 登录失败
}
19. 主菜单与功能分发
Q: 如何实现主菜单和功能分发?
A: 使用 switch结构根据用户选择调用对应方法。
/**
* 展示操作界面(主菜单)
*/
private static void showOperationUI() {
while (true) { // 循环显示菜单
System.out.println("----------员工管理系统操作界面----------");
System.out.println("1.查看员工");
System.out.println("2.添加员工");
System.out.println("3.修改员工");
System.out.println("4.删除员工");
System.out.println("0.退出系统");
System.out.print("请输入您的操作序号:");
int number = sc.nextInt();
// 功能分发
switch (number) {
case 1:
showEmployeeListUI(); // 查看员工
break;
case 2:
addEmployeeUI(); // 添加员工
break;
case 3:
updateEmployeeUI(); // 修改员工
break;
case 4:
deleteEmployeeUI(); // 删除员工
break;
case 0:
System.out.println("感谢使用,再见!");
System.exit(0); // 退出程序
default:
System.out.println("输入有误,请重新输入!");
}
}
}
20. 员工CRUD操作
Q: 如何实现员工的增删改查(CRUD)操作?
A:
// ========== 查询(Read)==========
/**
* 展现员工列表
*/
private static void showEmployeeListUI() {
System.out.println("----------查看员工----------");
System.out.println("编号\t\t姓名\t\t性别\t\t薪资\t\t部门");
// 使用Lambda遍历(或for-each)
employeeList.forEach(e -> {
System.out.println(e.getId() + "\t\t" +
e.getName() + "\t\t" +
e.getGender() + "\t\t" +
e.getSalary() + "\t\t" +
e.getDeptName());
});
}
// ========== 增加(Create)==========
/**
* 添加员工
*/
private static void addEmployeeUI() {
System.out.println("----------添加员工----------");
System.out.print("请输入员工编号:");
int id = sc.nextInt();
System.out.print("请输入员工姓名:");
String name = sc.next();
System.out.print("请输入员工性别:");
String gender = sc.next();
System.out.print("请输入员工薪资:");
double salary = sc.nextDouble();
System.out.print("请输入员工部门:");
String deptName = sc.next();
// 封装对象并添加
Employee employee = new Employee(id, name, gender, salary, deptName);
employeeList.add(employee);
System.out.println("添加员工成功!");
}
// ========== 修改(Update)==========
/**
* 修改员工
*/
private static void updateEmployeeUI() {
System.out.println("----------修改员工----------");
System.out.print("请输入要修改的员工编号:");
int id = sc.nextInt();
// 根据ID查找员工
Employee e = getEmployeeById(id);
if (e == null) {
System.out.println("编号无效,未找到对应员工!");
return;
}
System.out.println("找到员工:" + e);
// 录入新信息(直接修改对象,集合中的数据同步更新)
System.out.print("请输入新姓名:");
e.setName(sc.next());
System.out.print("请输入新性别:");
e.setGender(sc.next());
System.out.print("请输入新薪资:");
e.setSalary(sc.nextDouble());
System.out.print("请输入新部门:");
e.setDeptName(sc.next());
System.out.println("修改员工成功!");
}
// ========== 删除(Delete)==========
/**
* 删除员工
*/
private static void deleteEmployeeUI() {
System.out.println("----------删除员工----------");
System.out.print("请输入要删除的员工编号:");
int id = sc.nextInt();
Employee e = getEmployeeById(id);
if (e == null) {
System.out.println("编号无效,未找到对应员工!");
return;
}
employeeList.remove(e); // 从集合中删除
System.out.println("删除员工成功!");
}
// ========== 工具方法:根据ID查找员工 ==========
/**
* 根据ID查询员工对象
*/
private static Employee getEmployeeById(int id) {
for (Employee employee : employeeList) {
if (employee.getId() == id) {
return employee; // 找到返回
}
}
return null; // 未找到返回null
}