1. 反射1.1 认识反射反射允许对封装类的字段 方法和构造函数进行编程访问 用人话来说 就是用将一个类的成员变量 构造方法 成员方法全部提取出来 例如在idea中 自动提示就是靠反射来实现的对于字段 构造方法 成员方法这些 我们有可以获得他们一些具体的值 例如修饰词 名字 形参等如图所示 我们先要获取一个类的class对象 然后再去获取它的一些相关信息1.2 获取class对象的三种方法1.2.1Class.forname第一种方法是class.forname(全类名)全类名就是包名加类名的形式 一般用复制粘贴的形式去获取我们先定义一个类public class Student { private String name; private int age; public Student() { } public Student(String name, int age) { this.name name; this.age age; } private Student(String name){ this.namename; } public void introduce() { System.out.println(name - age); } }下面是演示Class clazzClass.forName(Student); System.out.println(clazz);1.2.2类名.class下面是演示Class clazzStudent.class; System.out.println(clazz);1.2.3对象.getclass下面是演示Student s new Student(); Class clazz s.getClass(); System.out.println(clazz);但是在一般情况下 我们直接用类名.class来获取Class对象1.3 反射获取构造方法1.3.1 获得所有构造方法常见方法有第一种方法使用来获取到所有的public构造方法如果在中间加上Declare那么该类的所有方法都会被获取到 这里我们创建一个Constructor数组来接收 然后使用增强for循环去打印Class clazz Student.class; Constructor[] constructors1 clazz.getConstructors(); Constructor[] constructors2 clazz.getDeclaredConstructors(); for (Constructor constructor : constructors1) { System.out.println(constructor); } for (Constructor constructor : constructors2) { System.out.println(constructor); }由上图可知 第一第二排是通过.getConstructors()这个方法获取的第三第四第五排是通过.getDeclaredConstructors()这个方法获取的1.3.2 获得指定的构造方法通过.getConstructor()和.getDeclaredConstructor(参数)这两种方法 去获取到指定的构造方法还是和上面一样 不加Decalare关键字获取不到非public的构造方法 而参数的格式为 类型.class 例如String.class,int.classConstructor cos1clazz.getConstructor(); Constructor cos2clazz.getDeclaredConstructor(String.class); System.out.println(cos1); System.out.println(cos2);1.3.3 获取构造方法的权限修饰符我们可以使用构造器种的.getModifiers()方法去获取到该方法的权限修饰符Constructor cos1clazz.getConstructor(); Constructor cos2clazz.getDeclaredConstructor(String.class); int modifiescos1.getModifiers(); int modifies2cos2.getModifiers(); System.out.println(modifies); System.out.println(modifies2);这里.getModifier()返回的是一个整数 不同的整数代表不同的权限修饰符号 例如1代表public 2代表private1.3.4 parameter相关方法parameter的意思是参数 相关方法主要有两种.getParameters()获取到所有的参数.getParameterCount()获取到参数个数Parameter []parameterscos3.getParameters(); int numcos3.getParameterCount(); System.out.println(num); for (Parameter parameter : parameters) { System.out.println(parameter); }1.3.5 利用获取到的构造器创建对象与暴力反射我们可以利用获取到的构造器 调用.newInstance()方法去new一个对象 但是需要强制类型转换注意: 如果该构造方法是私有的 我们不能直接创建对象 否则会报错正确的方法是前面加一个.setAccessible()方法 传递true值进去 表示临时取消权限 这个叫做暴力反射cos2.setAccessible(true); Student stu2(Student) cos2.newInstance(leixinrui); System.out.println(stu2);1.4 反射获取成员变量示例类public class Student { public int number; public String name; private int age; public Student(int number, String name) { this.number number; } public Student() { } public Student(String name, int age) { this.name name; this.age age; } private Student(String name) { this.name name; } public void introduce() { System.out.println(name - age); } }1.4.1 获取所有的成员变量与之前获取构造方法一样 成员变量的名字Field 一样的不加Declared代表获取public变量 加上代表获取所有成员变量Class clazz Student.class; Field[] fields1 clazz.getFields(); Field[] fields2 clazz.getDeclaredFields(); for(Field f:fields1) { System.out.println(f.getName()); } for(Field f:fields2){ System.out.println(f.getName()); }1.4.2 获取到指定的成员变量我们利用.getField()和.getDeclaredField(变量名)两种方法去获取到指定的变量Class clazz Student.class; Field field1clazz.getField(name); Field field2clazz.getDeclaredField(age); System.out.println(field2.getName()); System.out.println(field1.getName());原理与之前一样1.4.3 获取权限修饰符我们利用.getModifiers方法返回一个整数 与之前一样1代表public 2代表privateClass clazz Student.class; Field field1clazz.getField(name); Field field2clazz.getDeclaredField(age); System.out.println(field2.getName()); System.out.println(field1.getName()); int modifiers field1.getModifiers(); int modifiers2 field2.getModifiers(); System.out.println(modifiers2); System.out.println(modifiers);1.4.4 获取数据类型我们利用.getType()方法去获取到变量的类型 记得用泛型去接收Class? type field1.getType(); Class? type2 field2.getType(); System.out.println(type); System.out.println(type2);1.4.5 获取到成员变量值利用.get(类)方法去获取到成员变量值Student stu new Student(leixinrui,19); String value(String)field1.get(stu); System.out.println(value);1.5 获取方法1.5.1获取到所有的方法与之前一样我们 方法的名字叫做Method但与之前不同的是 如果我们不加Declared关键字 我们会获取到该类的父类的方法 加上Declared就不会获取到父类的方法Class clazz Student.class; Method[] methods1 clazz.getMethods(); Method[] methods2 clazz.getDeclaredMethods(); for (Method m : methods1) { System.out.println(m); } System.out.println(); for (Method m : methods2) { System.out.println(m); }1.5.2 获取到指定的方法2. 枚举2.1 什么是枚举枚举可以理解成装一些固定值的集合 如果一个东西只能从这几个值中选择 那么可以就用枚举2.2 枚举的使用定义如下 使用关键字enumpublic enum Gender { MALE, FEMALE }使用如下Gender gender Gender.MALE; System.out.println(gender); // 输出 MALE使用 枚举名.变量名的方法进行赋值2.3 为什么需要枚举在实际工作中 如果直接使用字符串直接命名 那么会出现打错了却不知道的情况 例如String status PAID; // 正确 String status PAYED; // 拼错了也不会报错运行时才发现问题如果使用枚举就不会出现这种情况 在编译初期 出现不该有的变量 编译器直接报错2.4 枚举中的方法枚举其实也是特殊的一种类 可以有自己的构造方法 与方法 但是有几个注意的点public enum OrderStatus { CREATED(已创建), PAID(已支付), SHIPPED(已发货), FINISHED(已完成), CANCELED(已取消); // 注意结尾分号 private String description; OrderStatus(String description) { this.description description; } public String getDescription() { return description; } }1.注意逗号与分号2.注意构造方法前什么修饰词都不用写 默认的是private枚举这一类自动继承了java.lang.Enum所以自带一下方法方法含义name()获取枚举值ordinal()获取枚举下标当前枚举值的下标 从0开始values()获取所有枚举值valueOf(String )输入一个字符串 返回一个枚举值下面是应用OrderStatus status OrderStatus.PAID; System.out.println(status.name()); // ① 输出PAID System.out.println(status.ordinal()); // ② 输出1 for (OrderStatus value : OrderStatus.values()) { // ③ 遍历所有常量 System.out.println(value - value.getDescription()); } OrderStatus parsed OrderStatus.valueOf(SHIPPED); // ④ 按名称解析 System.out.println(parsed.getDescription()); // 输出已发货3. 正则表达式3.1 什么是正则表达式在工作中 我们也能会遇到选哟进行字符串匹配或者说模糊搜索 这时候可以使用正则表达式例String phone 13812345678; boolean match phone.matches(1[3-9]\\d{9});3.2 正则表达式的书写符号含义.任意一个字符\\d数字\\D非数字\\w字母、数字、下划线\\W非字母、数字、下划线\\s空白字符\\S非空白字符[abc]a、b、c 中任意一个[^abc]不是 a、b、c 的字符[a-z]小写字母范围[A-Z]大写字母范围[0-9]数字范围值得注意的是 在 Java 字符串里反斜杠本身需要转义所以正则里的\d在 Java 代码里要写成\\d两个反斜杠用花括号括起来的是代表次数 用方括号括起来的是范围数量词含义?0 次或 1 次*0 次或多次1 次或多次{n}正好 n 次{n,}至少 n 次{n,m}n 到 m 次3.3 正则表达式的匹配我们可以在String后面跟上这些方法 用于字符串的匹配方法含义matches(regex)判断整个字符串是否匹配replaceAll(regex, replacement)替换所有匹配内容split(regex)按正则拆分matches方法用于匹配整个字符串 返回一个布尔值replaceAll方法用与替换匹配部分 第一个参数填正则 第二个参数填替换值split方法返回一个String[]数组 将正则表达式匹配的内容分开3.4 Pattern 和 Matcher3.4.1 Pattern的用途在实际工作中 我们可能会遇到不是整体匹配的情况 而是我们需要截取一个字符串中的一小部分 我们这个时候就需要用到Pattern3.4.2 创建正则与匹配器与之前学习的传统正则不同 我们需要创建一个Pattern正则表达式后 然后再创建一个匹配器 MatcherString text Alice:95, Bob:88, Cindy:76; Pattern p Pattern.compile(([A-Za-z]):(\\d)); Matcher m p.matcher(text); while (m.find()) { String name m.group(1); String score m.group(2); System.out.println(name 的成绩是 score); } // Alice 的成绩是 95 // Bob 的成绩是 88 // Cindy 的成绩是 76我们先创建一个Pattern对象 然后调用compile方法 去创建一个正则表达式然后创建一个Matcher匹配器 调用Pattern中的matcher方法创建 参数为我们需要匹配的字符串find()查找下一个匹配返回booleangroup()获取当前匹配的内容4. 日期时间APIJava 早期的Date、Calendar用起来不直观。现代 Java优先使用java.time包。常用类型类型含义LocalDate日期如 2026-06-22LocalTime时间如 10:30:15LocalDateTime日期和时间Instant时间戳Duration时间间隔时分秒Period日期间隔年月日DateTimeFormatter日期时间格式化工具4.1LocalDateLocalDate today LocalDate.now(); // 当前日期 LocalDate birthday LocalDate.of(2000, 5, 20); // 指定日期 today.getYear(); // 年 today.getMonthValue(); // 月 today.getDayOfMonth(); // 日在LocalDate一般利用两种方法去获取到LocalDate对象 一种是.now()方法 获取到当前时间一种是.of方法 获取到指定时间的的LocalDate对象 填入三个参数 年,月,日值得注意的是LocalDate类并不能获取到具体时间 只能获取到日期4.2LocalTime和LocalDateTime4.2.1 LocalTime与LocalDate一样 我们有两种方法去获取到LocalTime的对象import java.time.LocalTime; LocalTime now LocalTime.now(); // 当前时间如 14:35:20.123 LocalTime fixed LocalTime.of(10, 30, 15); // 指定 10:30:15 System.out.println(now.getHour()); // 时 System.out.println(now.getMinute()); // 分 System.out.println(now.getSecond()); // 秒一个是.now()一个是.of() 一样的 一个用来获取当前的时间 一个用来获取指定时间 传入的参数格式为 时分秒4.2.2 LocalDateTime相对于前面两个LocalDateTime结合了之间两个类的邮电 既有日期 又有时间 但是美中不足的时LocalDateTime并不能显示出时区import java.time.LocalDateTime; LocalDateTime now LocalDateTime.now(); // 2026-10-12T14:35:20.123 LocalDateTime fixed LocalDateTime.of(2026, 6, 22, 10, 30); // 指定日期时间 System.out.println(now.getYear()); // 2026 System.out.println(now.getMonthValue()); // 10 System.out.println(now.getDayOfMonth()); // 12方法与之前的无异类型包含内容典型例子LocalDate只有日期2026-10-12LocalTime只有时间14:35:20LocalDateTime日期 时间2026-10-12T14:35:20值得注意的是 这三个类之间可以相互转换LocalDateTime dt LocalDateTime.now(); LocalDate date dt.toLocalDate(); // 取出日期部分 LocalTime time dt.toLocalTime(); // 取出时间部分 LocalDateTime combined date.atTime(time); // 组合成日期时间4.3 日期时间加减方法含义plusDays/minusDays增加/减少天数plusMonths/minusMonths增加/减少月数plusYears/minusYears增加/减少年数plusHours/minusHours增加/减少小时LocalTime/LocalDateTimeplusMinutes/minusMinutes增加/减少分钟我们可以在之前介绍的三个类中调用这些方法 但值得注意的是 第哦啊用这些方法是发那会一个新的对象 而不是是在原有的对象上进行加减LocalDate today LocalDate.now(); today.plusDays(7); // 7 天后 today.minusMonths(1); // 1 个月前 LocalDateTime now LocalDateTime.now(); now.plusHours(2); // 2 小时后4.4 格式化和解析4.4.1 出现的原因格式化和解析的出现本质上是为了解决我们之前介绍的那三类不能转化成字符串的问题 如果我们直接打印之前的对象 那么我们得到是一个ISO格式 不方便观看System.out.println(LocalDateTime.now()); // 2026-10-12T14:30:05.123456 System.out.println(LocalDateTime.of(2026, 6, 22, 10, 30)); // 2026-06-22T10:30 System.out.println(LocalDateTime.of(2026, 6, 22, 10, 30, 15)); // 2026-06-22T10:30:15所以我们有了格式化和解析 方便转化成我们先要的字符串 便于观看格式化是将类转化成字符串 解析是把字符串转化成类而在这之前 我们可以用ofPattern方法去美化时间4.4.2 使用方法符号含义yyyy年MM月dd日HH24 小时制小时mm分钟ss秒LocalDateTime now LocalDateTime.now(); DateTimeFormatter formatter DateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss); // 1. 格式化对象 → 字符串 String text now.format(formatter); System.out.println(text); // 例如2026-06-22 10:30:00 // 2. 解析字符串 → 对象 LocalDateTime parsed LocalDateTime.parse(2026-06-22 10:30:00, formatter); System.out.println(parsed); // 输出2026-06-22T10:30我们来看看是怎么使用的先创建一个DateTimeFormatter对象 使用ofPattern方法 传入我们需要的格式如第一幅图formate和parse是我们使用中最重要的两个方法formate负责把时间类转化为String类 parse方法负责把字符串转化成时间类 传递两个参数 第一个是字符串 第二个是我转化成的格式4.5Duration和Period这两个时间类是用来计算间隔Duration类用来计算时间间隔Period用来计算日期间隔 他们使用的方法都是调用.between()方法 传递两个时间类 表示开始时间和结束时间import java.time.LocalDate; import java.time.Period; public class PeriodDemo { public static void main(String[] args) { LocalDate start LocalDate.of(2020, 1, 1); LocalDate end LocalDate.of(2026, 6, 22); Period period Period.between(start, end); System.out.println(period.getYears()); System.out.println(period.getMonths()); System.out.println(period.getDays()); } }import java.time.Duration; import java.time.LocalDateTime; public class DurationDemo { public static void main(String[] args) { LocalDateTime start LocalDateTime.of(2026, 6, 22, 10, 0); LocalDateTime end LocalDateTime.of(2026, 6, 22, 12, 30); Duration duration Duration.between(start, end); System.out.println(duration.toHours()); System.out.println(duration.toMinutes()); } }5. Lambda表达式5.1 Lambda表达式的介绍在学习Lambda表达式之前 我们需要认识一下匿名内部类5.1.1 匿名内部类在实际工作中 我们可能会遇到一下情况1.创建了一个接口 但我们只需要使用一次 而又懒得重新创建一个类去实现2.创建了一个抽象类 但我们懒得去又创建一个新的类去继承 然后再来重写里面的方法为了解决这些问题 我们发明了匿名内部类5.1.2 匿名内部类的使用new 父类或接口() { // 这里写方法的具体实现 };我们来理解一下这里new的是括号里面的方法或者接口相当于new一个类或者接口// 接口只有一个方法 interface Greeting { void sayHello(); } public class Test { public static void main(String[] args) { // 匿名内部类直接 new 接口 大括号实现方法 Greeting g new Greeting() { public void sayHello() { System.out.println(你好); } }; g.sayHello(); // 输出你好 } }我们相当于没有经过我们之前学习的需要创建一个类 然后实现这个接口 而是相当于直接创建了一个接口对象5.2 Lambda表达式的使用Lambda表达式的出现就是为了解决匿名内部类太麻烦的问题 相当于更加代码更加简洁 更注重于代码需要实现的功能本身 而不是一个对象 不在是面向对象的思想// 以前 for (String name : names) { System.out.println(name); } // 现在 names.forEach(name - System.out.println(name));我们观察以前的代码 我们使用了增强for循环 而现在Lambda表达式的出现 我们更加强调 谁参数去做什么方法我们直接写name(谁)-System.out.println(name)(去干什么) 代码更加简单5.3 函数式接口Lambda 只能用于函数式接口。函数式接口是只有一个抽象方法的接口。FunctionalInterface public interface Calculator { int calculate(int a, int b); }使用 Lambdapublic class FunctionalInterfaceDemo { public static void main(String[] args) { Calculator add (a, b) - a b; Calculator multiply (a, b) - a * b; System.out.println(add.calculate(10, 20)); System.out.println(multiply.calculate(10, 20)); } }6. Stream流6.1 Stream流介绍在之前 我们比如说在遍历一个数组的时候 我们需要创建一大堆的临时变量 然后使用if判断等等进行筛选 所以我们发明了Stream流去简化我们的步骤// 传统写法筛选出及格分数 ListInteger passed new ArrayList(); for (Integer score : scores) { if (score 60) { passed.add(score); } }使用Stream流ListInteger passed scores.stream() .filter(score - score 60) .toList();6.2 Stream流的使用我们使用一般使用以下步骤① 创建 Stream → ② 中间操作可多个链式 → ③ 终结操作只能一个放在最后6.2.1 创建Stream流方式代码从集合list.stream()从数组Arrays.stream(arr)或Stream.of(1, 2, 3)直接用元素Stream.of(a, b, c)1.Collection 接口创建ListString list new ArrayList(); list.add(a); StreamString s1 list.stream(); // 串行流默认最常用 StreamString s2 list.parallelStream(); // 并行流多线程处理对于ArrayList这样的数组 我们直接使用.stream()方法去创建Stream对象2.数组创建int[] nums {1, 2, 3, 4}; IntStream intStream Arrays.stream(nums); // 基本类型数组 → IntStream String[] strs {a, b}; StreamString strStream Arrays.stream(strs); // 对象数组 → StreamT对于数组 我们可以调用Arrays中的stream方法创建 括号中传入目标数组3.Stream.of(元素...)StreamString s1 Stream.of(a, b, c); // 直接列举元素 StreamString s2 Stream.of(strs); // 传对象数组值得注意的是tream.of传基本类型数组时不会拆开而是把整个数组当成一个元素int[] nums {1, 2, 3}; Streamint[] s Stream.of(nums); // ❌ 得到的是 Streamint[]只有一个元素整个数组6.2.2 中间操作中间操作使得我们可以对Stream中的数据进行筛选 常见方法如下方法含义filter筛选map转换sorted排序distinct去重limit截取前几个skip跳过前几个而我们在实际工作中 会使用链式法则去使用方法 一般最后会跟上foreach方法结合Lambda表达式去遍历1. filter —— 筛选保留符合条件的.filter(score - score 60) // 只保留 60 的参数是一个PredicateTtest返回 boolean。2. map —— 转换把一个元素变成另一个元素.map(name - name.length()) // String 转成 Integer .map(Student::getName) // Student 转成 name参数是FunctionT, R输入类型和输出类型可以不同。区分filter是留/不留元素还是原来那个个数可能变map是变元素类型/值变了个数不变。3. sorted —— 排序.sorted() // 自然排序要求元素可比较 .sorted((a, b) - b.getScore() - a.getScore()) // 自定义按分数降序 .sorted(Comparator.comparing(Student::getScore).reversed()) // 更推荐的可读写法4. distinct —— 去重.distinct() // 按 equals 去重5. limit —— 截取前几个.limit(3) // 只保留前 3 个6. skip —— 跳过前几个.skip(2) // 跳过前 2 个limit(n)和skip(n)配合可以做分页。6.2.3 终结终结操作会结束 Stream。方法含义forEach遍历count统计数量toList收集为列表anyMatch是否任意元素匹配allMatch是否所有元素匹配noneMatch是否没有元素匹配findFirst查找第一个元素reduce归约计算import java.util.ArrayList; public class StreamTerminalDemo { public static void main(String[] args) { ArrayListInteger scores new ArrayList(); scores.add(95); scores.add(88); scores.add(58); long passCount scores.stream() .filter(score - score 60) .count(); boolean hasFullScore scores.stream() .anyMatch(score - score 100); System.out.println(passCount); System.out.println(hasFullScore); } }这些方法不一一介绍