《Java 100 天进阶之路》第20篇:Java初始化、构造器、对象创建的过程

第20篇:Java初始化、构造器、对象创建的过程


📌 系列导航《Java 100 天进阶之路》完整目录 |

⬅️ 上一篇:第19篇:Java接口的作用和意义 |

➡️ 下一篇:第21篇:Java Object类


一、核心知识点

  • 成员初始化顺序:
    • 静态成员(静态变量、静态代码块)在类加载时执行,按声明顺序执行
    • 实例成员(实例变量、实例代码块)在创建对象时执行,在构造方法之前执行
    • 构造方法最后执行
  • 构造器(构造方法)的作用:初始化对象状态
  • 对象创建的完整流程(JVM 角度):
    1. 类加载检查(如果类未加载,先加载)
    2. 堆中分配内存
    3. 设置默认值(零值)
    4. 设置对象头(类型指针、GC 信息等)
    5. 执行实例初始化:实例变量显式赋值 → 实例代码块 → 构造方法
  • 父子类初始化顺序:先父类静态 → 子类静态 → 父类实例变量/代码块 → 父类构造 → 子类实例变量/代码块 → 子类构造

二、通俗讲解(1分钟开心学)

1. 初始化过程就像"盖房子"

  • 类加载:先设计图纸(静态成员),只做一次。
  • 对象创建:每次建房,都要打地基(默认值)、砌墙(显式赋值)、内部装修(实例代码块)、最后交房(构造方法)。

2. 静态成分(类级别)

当你第一次使用一个类时(new、访问静态变量/方法、Class.forName等),JVM 会加载这个类,并执行:

  • 静态变量赋值
  • 静态代码块(按代码顺序)

3. 实例成分(对象级别)

每次 new 一个对象,都会执行:

  • 实例变量显式赋值
  • 实例代码块({ ... } 中的内容,按顺序)
  • 构造方法

4. 继承时的顺序

想象你创建子类对象,必须先给父类"打好地基":

父类静态 → 子类静态 → 父类实例初始化 → 父类构造 → 子类实例初始化 → 子类构造

面试口诀

"父静子静,父实父构,子实子构"

三、实操代码案例 + 场景说明

场景:通过打印日志,直观看到初始化的完整顺序。

1. 单个类的初始化顺序

java 复制代码
class Student {
    private String name = initName();   // 实例变量显式赋值
    private static int counter = initCounter();  // 静态变量
    
    static {
        System.out.println("2. 静态代码块执行");
    }
    
    {
        System.out.println("4. 实例代码块执行");
    }
    
    public Student() {
        System.out.println("5. 构造方法执行");
    }
    
    private static int initCounter() {
        System.out.println("1. 静态变量赋值 (initCounter)");
        return 0;
    }
    
    private String initName() {
        System.out.println("3. 实例变量赋值 (initName)");
        return "默认";
    }
}

// 执行 new Student() 输出:
// 1. 静态变量赋值
// 2. 静态代码块执行
// 3. 实例变量赋值
// 4. 实例代码块执行
// 5. 构造方法执行

2. 继承时的完整顺序

java 复制代码
class Parent {
    static { System.out.println("A. 父类静态块"); }
    { System.out.println("C. 父类实例块"); }
    Parent() { System.out.println("D. 父类构造方法"); }
}

class Child extends Parent {
    static { System.out.println("B. 子类静态块"); }
    { System.out.println("E. 子类实例块"); }
    Child() { System.out.println("F. 子类构造方法"); }
}

// 执行 new Child() 输出:
// A. 父类静态块
// B. 子类静态块
// C. 父类实例块
// D. 父类构造方法
// E. 子类实例块
// F. 子类构造方法

3. 对象创建的内存流程(代码配合注释)

java 复制代码
public class MemoryProcess {
    private int value = 100;   // ① 默认值0 → ② 显式赋值为100
    private String text;       // 默认null,没有显式赋值
    
    public MemoryProcess(String text) {
        this.text = text;      // ③ 构造方法中赋值
    }
}
// 执行 new MemoryProcess("hello"):
// 1. 堆中分配内存
// 2. value = 0, text = null (默认值)
// 3. value = 100 (显式赋值)
// 4. text = "hello" (构造方法)

四、避坑要点

错误/误区 后果 正确做法
在静态代码块中访问实例成员 编译错误 静态上下文只能访问静态成员
实例代码块中抛出未捕获异常 对象创建失败,异常传播给调用者 尽量不在实例代码块中写复杂逻辑
构造方法中调用可被子类重写的方法 子类未初始化完成,可能空指针 只调用 privatefinal 方法
this()super() 同时出现在构造方法中 编译错误 只能选其一,且必须在第一行

五、面试高频考点

Q1:静态代码块、实例代码块、构造方法的执行顺序?

类加载:静态代码块。对象创建:实例变量显式赋值和实例代码块(按顺序) → 构造方法。继承时先父类后子类。

Q2:一个对象创建时,内存中发生了什么?

① 类加载(如果没加载)→ ② 堆中分配内存 → ③ 成员变量设默认值 → ④ 设置对象头 → ⑤ 实例初始化(显式赋值、实例代码块、构造方法)。

Q3:构造方法中调用普通方法有什么风险?

如果该方法被子类重写,调用时会执行子类版本,而此时子类的成员可能尚未初始化(null 或 0),导致逻辑错误或空指针。

六、练习题

  1. 预测输出

    java 复制代码
    class A {
        static { System.out.print("A1 "); }
        { System.out.print("A2 "); }
        A() { System.out.print("A3 "); }
    }
    class B extends A {
        static { System.out.print("B1 "); }
        { System.out.print("B2 "); }
        B() { System.out.print("B3 "); }
    }
    public class Test { public static void main(String[] args) { new B(); } }
  2. 代码改错 :下面代码哪里有问题?如何修正?

    java 复制代码
    class Base {
        public Base() { print(); }
        void print() { System.out.println("Base"); }
    }
    class Derived extends Base {
        private String value = "Hello";
        @Override void print() { System.out.println(value.toUpperCase()); }
    }
  3. 动手 :写一个类,包含静态代码块、实例代码块、构造方法,并在 main 中创建多个对象,观察输出。


📊 你的学习进度

  • 当前:第20篇 / 共44篇 · 第二阶段:核心语法与面向对象(第5~20篇)
  • ✅ 已完成:第1~19篇
  • 📖 正在学:第20篇
  • ⏳ 待学习:第21~44篇

👉 📚 完整目录 & 学习指南 | 🔥 订阅本专栏,不错过每一篇

💡 本专栏每篇都包含:避坑表 + 面试高频考点 + 练习题。每天30分钟,100天拿offer!


👉 下一篇预告

《Java Object类》

内容简介:toString、equals、hashCode的正确重写规范,equals与hashCode的契约,getClass、clone方法。

💡 学完这篇,你将掌握所有类的共同"祖先",写出规范的Java Bean。

📌 《Java 100 天进阶之路 | 从入门到上岗就业》 每天一篇,建议收藏 + 关注 ,一起100天拿offer!

👉 点击关注我,更新后第一时间收到推送!

相关推荐
cjp5604 分钟前
009. ASP.NET WEB API 用户关联esp32设备
前端·后端·asp.net
贺国亚10 分钟前
Text-to-SQL与Analytics-Agent
后端
小熊美家熊猫系统18 分钟前
电子合同技术实现与合规实践
java·开发语言·分布式
云烟成雨TD18 分钟前
Agent Scope Java 2.x 系列【3】从零构建 ReActAgent
java·人工智能·agent
ytttr87321 分钟前
C# 定时数据库备份工具
开发语言·数据库·c#
一只叫煤球的猫28 分钟前
ThreadForge 源码解读二:一个 Task 从 submit 到完成,内部到底发生了什么?
java·后端·面试
苏三说技术41 分钟前
AgentScope Java 2.0 正式发布了!
后端
skywalk81631 小时前
言知项目后续方向建议
开发语言·学习·编程
ping某1 小时前
一个“日志备份”需求,为什么会牵出整个 Linux 日志系统?
后端·架构
阿狸猿1 小时前
论微服务架构及其应用
java·微服务·架构