1.创建对象的过程?

“当 JVM 遇到一条字节码 new 指令时,创建对象的过程主要分为 五步:
第一步:类加载检查 (Class Loading Check)
-
JVM 首先会去检查这个指令的参数,看能不能在常量池中定位到一个类的符号引用。
-
然后检查这个符号引用代表的类是不是已经被加载、解析和初始化过。
-
如果没有,那必须先执行相应的 类加载过程(Loading → Linking → Initializing)。
第二步:分配内存 (Memory Allocation) —— 核心点
-
类加载检查通过后,JVM 就知道这个对象需要多大的内存了(类加载完大小就确定了)。
-
接下来会在 堆 (Heap) 中划分一块内存给这个对象。
-
(这里涉及‘指针碰撞’和‘空闲列表’两种分配方式,视堆内存是否规整而定)。
第三步:初始化零值 (Zero Initialization)
-
内存分配完后,JVM 需要将分配到的内存空间都初始化为 零值(不包括对象头)。
-
这就是为什么我们在 Java 代码中定义成员变量 int i,不赋值直接用也不会报错(因为默认是 0)。
第四步:设置对象头 (Setting Object Header)
-
JVM 要对对象进行必要的设置:比如这个对象是哪个类的实例、如何找到类的元数据、对象的哈希码、对象的 GC 分代年龄等信息。
-
这些信息都存放在 对象头 (Object Header) 中。
第五步:执行 <init> 方法 (Execution)
-
上面 4 步做完,从 JVM 角度看对象已经造好了,但从 Java 程序的角度看,对象才刚刚开始。
-
此时会执行构造函数(也就是字节码里的
<init>方法),按照我们的意愿对对象进行初始化(赋值)。 -
执行完这一步,一个真正可用的对象才算完全产生。”
2.对象的生命周期
创建:对象通过关键字new在堆内存中被实例化,构造函数被调用,对象的内存空间被分配。 使用:对象被引用并执行相应的操作,可以通过引用访问对象的属性和方法,在程序运行过程中被不断使用。 销毁:当对象不再被引用时,通过垃圾回收机制自动回收对象所占用的内存空间。垃圾回收器会在适当的时候检测并回收不再被引用的对象,释放对象占用的内存空间,完成对象的销毁过程。
3.类加载器有哪些?

“在 Java (JDK 8) 中,主要有 3 个核心类加载器,它们是层级关系的:
1. 启动类加载器 (Bootstrap ClassLoader)
-
地位: 老祖宗。它是最顶层的加载器。
-
实现: 由 C++ 编写(所以在 Java 代码里拿不到它的引用,是一个
null)。 -
职责: 负责加载 Java 的核心类库。
-
路径: 加载
JAVA_HOME/lib目录下的 jar 包(比如rt.jar,里面有String,System这些最基础的类)。
2. 扩展类加载器 (Extension ClassLoader)
-
地位: 二把手。
-
实现: Java 编写。
-
职责: 负责加载 Java 的扩展库。
-
路径: 加载
JAVA_HOME/lib/ext目录下的 jar 包。里面有压缩,js 引擎,加密,国际语言
3. 应用程序类加载器 (Application ClassLoader)
-
地位: 干活的主力。也叫系统类加载器 (System ClassLoader)。
-
实现: Java 编写。
-
职责: 负责加载我们自己写的代码和引用的第三方 jar 包。
-
路径: 加载
CLASSPATH环境变量指定的路径。
4. 自定义类加载器 (Custom ClassLoader)
- 职责: 如果我们需要从网络、加密文件或非标准路径加载类,可以继承
ClassLoader类来实现自己的加载逻辑(比如 Tomcat 就自定义了很多)。”
形象比喻:家族企业
把 JVM 想象成一个 “家族企业”,找东西(加载类)的时候有严格的等级制度:
-
Bootstrap (爷爷 - 创始人):
- 只管最核心的机密文件(JDK 核心库)。他看不懂中文(Java),只懂底层(C++)。
-
Extension (爸爸 - 分公司老总):
- 管一些扩展业务(Ext 库)。
-
Application (你 - 基层员工):
- 管所有日常杂活(你的业务代码)。
-
Parent Delegation (双亲委派):
-
当你需要找一个文件(类)时,你不敢自己先找,必须先问爸爸:“爸,这东西你有吗?”
-
爸爸也不敢自己找,先问爷爷:“爹,这东西你有吗?”
-
爷爷说“没有” → 爸爸才敢找。
-
爸爸也说“没有” → 你才敢自己找。
-
4.为什么要设计成这样一层层往上问?(为什么要双亲委派?)
“主要为了解决 安全 和 唯一性 的问题:
-
避免重复加载 (唯一性):
-
如果没有双亲委派,我自己写了个
java.lang.String,你又写了个java.lang.String。 -
JVM 就乱套了,不知道该用哪一个。
-
有了双亲委派,无论谁要加载
String,最终都会委派给爷爷 (Bootstrap)。爷爷发现他已经加载过官方的String了,直接返回,保证了核心类在内存中只有一份。
-
-
保证安全 (沙箱安全机制):
-
如果黑客自定义了一个
java.lang.System类来替换核心类,里面写了恶意代码。 -
如果没有双亲委派,这个恶意类就被加载进来了。
-
有了双亲委派,JVM 根本不会理会黑客写的这个类,因为爷爷那里已经有一份正版的
System了。”
-
_5.双亲委派模型的作用
6.讲一下类加载过程?

| 阶段 | 术语 | 比喻 | 解释 |
|---|---|---|---|
| 1 | 加载 | 买房拿钥匙 | 找到房子(Class文件),拿到钥匙(Class对象),进门了。 |
| 2.1 | 验证 | 验房 | 检查墙体有没有裂缝,是不是危房(由 CAFEBABE 验证)。 |
| 2.2 | 准备 | 刮大白/硬装 | 先把墙刷白,家具还没进场。此时只有空壳子(变量赋零值:int=0)。 |
| 2.3 | 解析 | 接通水电 | 把图纸上的“插座位置”变成墙上真正的“电线接口”(符号引用 → 内存地址)。 |
| 3 | 初始化 | 软装/入住 | 按照你的喜好摆放沙发、挂画(执行 static 赋值和代码块),房子真正可以用了。 |
-
顺序:类加载(备案图纸) $\rightarrow$ 对象创建(按图盖房)。
-
关系:类是模板(1个),对象是实例(N个)。对象引用类,但不被类包含。
-
空间:类在元空间,对象在堆。
7.讲一下类的加载和双亲委派原则
“双亲委派模型其实是服务于类加载过程中‘加载 (Loading)’这一阶段的。
比如我要
new User():
加载阶段:JVM 发现还没加载
User类,于是启用双亲委派,AppClassLoader 问 Ext,Ext 问 Boot,Boot 说没有,最后 AppClassLoader 自己把User.class文件读进来。连接阶段:给
User里的static变量赋零值。初始化阶段:执行
static代码块。这样
User类就算彻底加载完了。”
| 维度 | 类的加载过程 (Process) | 双亲委派原则 (Mechanism) |
|---|---|---|
| 关注点 | 生命周期 (做什么事?) | 层级规则 (谁来做?) |
| 核心步骤 | 加载 → 连接(验证/准备/解析) → 初始化 | App → Ext → Boot (向上委托,向下加载) |
| 关系 | 包含关系 (双亲委派是”加载”步骤的策略) | 服务关系 (服务于类的安全性与唯一性) |