本阶段涵盖:类加载机制与反射、反射 Field 字段反射与 Method 方法反射 细分文档:
按日细分/20260812-笔记.md、按日细分/20260813-笔记.md学生需要重点理解、背诵、掌握的理论核心知识点。
.java 源文件 --编译--> .class 字节码 --类加载器--> 内存 --> JVM 解释 --> 二进制机器码 --> 执行
.class 字节码平台无关 → Java 跨平台原理| # | 触发场景 | 示例 |
|---|---|---|
| ① | 创建类的实例对象 | new Demo01() |
| ② | 调用 static 方法 | Math.abs(-1) |
| ③ | 访问/赋值 static 变量 | Student.school = "..." |
| ④ | 反射创建 Class 对象 | Class.forName("...") |
| ⑤ | 初始化子类(先加载父类) | new SubStudent() |
| ⑥ | Java.exe 运行主类 | java course.Demo01 |
懒加载原则:使用时才加载。初始化子类先触发父类加载(先父后子)。
1. 加载(Loading):通过全限定名获取字节流 → 生成 java.lang.Class 对象
2. 链接(Linking)
├── 验证(Verify):检查字节流符合规范、无安全隐患
├── 准备(Prepare):为 static 变量分配内存并设默认值(int→0)
└── 解析(Resolve):符号引用 → 直接引用;用到其他类在此查找
3. 初始化(Initialization):执行静态变量赋值、静态代码块
一句话:加载"搬文件"、验证"查安全"、准备"分默认内存"、解析"找引用的类"、初始化"跑初始化代码"。
静态代码块(类加载初始化阶段,只执行一次)→ 普通代码块(每次 new,构造前)→ 构造方法
| 类加载器 | 职责 | 父加载器 |
|---|---|---|
| BootstrapClassLoader(启动) | 最核心 JDK 类 | 无(表示为 null) |
| PlatformClassLoader(平台) | JDK 特殊模块 | Bootstrap |
| SystemClassLoader(系统) | 用户类路径的类 | Platform |
ClassLoader.getSystemClassLoader() → 逐级 getParent()概念:类加载器收到加载请求不自己先加载,先委派给父加载器,递归到最顶层;顶层能加载就成功,顶层不行才由子加载器尝试。
为什么需要双亲委派(三原因必背):
java.lang.String 永远不会被加载ClassLoader cl = ClassLoader.getSystemClassLoader();
InputStream in = cl.getResourceAsStream("prop.properties"); // classpath 根目录
Properties pro = new Properties();
pro.load(in);
String driver = pro.getProperty("db.driver");
in.close();
load() 加载、getProperty(key) 取值反射是 Java 的运行时动态机制:运行状态中能获取任意类的所有属性方法(包括 private)、调用任意对象的任意属性和方法。反射是 Spring/MyBatis/Hibernate/JDBC 等框架的基础。
| 维度 | 普通调用 | 反射调用 |
|---|---|---|
| 获取信息时机 | 编译期写死 | 运行时动态 |
| 依赖关系 | 强耦合 | 解耦 |
| 创建对象 | new 类名() |
Class.forName() + newInstance() |
| 调用方法 | 对象.方法() |
method.invoke(对象, 参数) |
| 灵活性 | 固定 | 高度灵活 |
日常业务开发尽量不用反射(像开挂):①可能破坏封装性(能拿 private)②效率低(比正常创建低 3~100 倍)。
学习反射的目的:理解框架底层源码 + 架构/中间件做解耦适配。
Person.java → javac → Person.class → 类加载器 → Class 对象(类的类模板)
├── Constructor → newInstance() 创建对象
├── Field → get/set 读写字段
└── Method → invoke() 执行方法
Class(反射入口)/ Constructor(创建对象)/ Field(读写字段)/ Method(调用方法)/ Modifier(解析修饰符)/ Parameter(方法参数)
| 方式 | 写法 | 特点 |
|---|---|---|
| 方式一 | Student.class |
最直接,编译期类型检查 |
| 方式二 | student.getClass() |
Object 方法,需有对象 |
| 方式三 | Class.forName("course.Student") |
字符串传类名最灵活,框架最常用;写错抛 ClassNotFoundException |
三个重要验证:
int.class == Integer.TYPEClass.forName() 会触发静态代码块;类名.class 和 对象.getClass() 不触发查看类型信息: getName()(全类名)/ getSimpleName() / getSuperclass() / getPackage()
4 个获取 API:
| 方法 | 是否含 private |
|---|---|
getConstructors() |
❌ 只 public |
getConstructor(Class...) |
❌ 只 public |
getDeclaredConstructors() |
✅ 含私有 |
getDeclaredConstructor(Class...) |
✅ 含私有 |
暴力反射: 私有构造直接 newInstance() 报权限错,先 setAccessible(true) 放开权限。
Constructor<?> dc = studentClass.getDeclaredConstructor(String.class, Integer.class);
dc.setAccessible(true);
Object o = dc.newInstance("张三", 1001);
反射受检异常: ClassNotFoundException / NoSuchMethodException / InstantiationException / IllegalAccessException / InvocationTargetException
Field 对象代表类中的一个成员变量。 get() 读、set() 写。
框架典型应用:ORM 框架把数据库数据映射到 Java 类,用的就是 Field.set()(ORM 底层原理)。
| 方法 | 含 private | 含父类继承 |
|---|---|---|
getFields() |
❌ | ✅ |
getField(name) |
❌ | ✅ |
getDeclaredFields() |
✅ 本类全部 | ❌ |
getDeclaredField(name) |
✅ | ❌ |
get(obj) 读值 / set(obj, 值) 赋值 / setAccessible(true) 暴力反射 / getType() 类型 / getName() 属性名 / getModifiers() 修饰符(int,Modifier.toString() 解析)
| 场景 | get 参数 | set 参数 | 原因 |
|---|---|---|---|
| 实例属性 | get(对象) |
set(对象, 值) |
属于某个对象 |
| 静态属性 | get(null) |
set(null, 值) |
属于整个类 |
// ① 遍历所有属性,输出修饰符+类型+属性名
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
System.out.println(Modifier.toString(f.getModifiers()) + " " + f.getType().getSimpleName() + " " + f.getName());
}
// ② 操作 public 字段
Field emailField = clazz.getField("email");
emailField.get(s); emailField.set(s, "lisi@qq.com");
// ③ 操作 private 字段(暴力反射)
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true); nameField.get(s); nameField.set(s, "李四");
// ④ 操作 static 字段(传 null)
Field schoolField = clazz.getDeclaredField("school");
schoolField.get(null); schoolField.set(null, "新学校");
Method 对象代表类中的一个方法。 反射通过 Method.invoke(对象, 参数...) 调用方法,等价于 对象.方法(参数)——方法名称和参数运行时才确定。
应用:动态代理、测试框架(JUnit)、注解解释器、框架调用 setter/getter。
| 方法 | 含 private | 含父类/接口继承 |
|---|---|---|
getMethods() |
❌ | ✅(含 toString/hashCode) |
getMethod(name, parameterTypes) |
❌ | ✅ |
getDeclaredMethods() |
✅ 本类全部 | ❌ |
getDeclaredMethod(name, parameterTypes) |
✅ | ❌ |
重载方法必须指明参数类型(必背):
getMethod("setName", String.class) // String.class 用来区分同名重载
不写或写错参数类型都抛
NoSuchMethodException。
invoke(obj, args) 调用 / setAccessible(true) 暴力反射 / getReturnType() 返回值类型 / getParameterTypes() 参数类型数组 / getModifiers() 修饰符
| 方法类型 | invoke 写法 |
|---|---|
| public 实例方法 | invoke(对象, 参数...) |
| static 静态方法 | invoke(null, 参数...) |
| void 无返回值方法 | 调用后返回 null |
| private 私有方法 | 先 setAccessible(true) 再 invoke |
| 成员 | 取多个(数组) | 取单个 | 含私有数组 | 含私有单个 |
|---|---|---|---|---|
| 属性 | getFields() |
getField(name) |
getDeclaredFields() |
getDeclaredField(name) |
| 方法 | getMethods() |
getMethod(name, 参数类型...) |
getDeclaredMethods() |
getDeclaredMethod(name, 参数类型...) |
| 构造 | getConstructors() |
getConstructor(参数类型...) |
getDeclaredConstructors() |
getDeclaredConstructor(参数类型...) |
口诀(贯穿三组):含
Declared的能拿私有(本类全部),不含Declared的只能拿 public(含父类/接口继承)。
| 类别 | 关注点 | 关键方法 |
|---|---|---|
| Field 属性 | 属性组成部分 | 名字 getName、修饰符 getModifiers、值 get/set |
| Method 方法 | 方法组成部分 | 名字 getName、执行 invoke、返回值 getReturnType、参数 getParameterTypes、修饰符 getModifiers |
| Constructor 构造 | 构造组成部分 | 修饰符 getModifiers、参数 getParameterTypes、创建 newInstance |
getDeclaredXxx 拿私有 + setAccessible(true) 放开权限 + 执行操作(Constructor→newInstance / Field→get/set / Method→invoke);操作静态成员(属性/方法)对象参数传 null。