单例模式 饿汉式(静态语句块)

/**
 * 单例模式
 * 饿汉式  方式2 静态代码块
 * 缺点:实例instance随类的加载而被创建,一直不用会造成内存浪费。
 */
public class SingletonEager {
    // 1、私有化构造方法
    private SingletonEager(){}
    // 2、声明一个对象
    private static SingletonEager inatance;
    // 在静态代码块中创建对象
    static {
        inatance = new SingletonEager();
    }
    // 3、对外提供静态方法获取唯一实例
    public static SingletonEager getInstance() {
        return inatance;
    }
}

下面详细拆解 static 在这里的三个作用,以及为什么它能保证对象唯一。

一、 static 关键字的三个关键作用

在代码中,static 用在了三个地方,它们共同协作完成了单例逻辑:

1. 静态变量 (static SingletonEager instance)

  • 作用: 将变量归属于类(Class),而不是归属于某个具体的对象。
  • 结果: 无论这个类被后面用到了多少次,内存中只有一份 instance 变量。它存储在方法区(Method Area)或元空间中,被所有对象共享。

2. 静态代码块 (static { ... })

  • 作用: 用于类的初始化。
  • 触发时机: 当 JVM(Java 虚拟机)第一次加载这个类的时候执行。
  • 次数: 在整个程序的生命周期内,类只会被加载一次,所以静态代码块只执行一次
  • 结果: instance = new SingletonEager(); 这行代码只跑了一次,所以对象只创建了一个。

3. 静态方法 (static SingletonEager getInstance())

  • 作用: 允许在不创建对象的情况下直接调用方法。
  • 原因: 如果不是 static 方法,想调用 getInstance() 就必须先 new SingletonEager(),但这陷入了死循环(因为构造方法是私有的,外部无法 new)。
  • 用法: 变成了通过类名直接调用:SingletonEager.getInstance()

二、 为什么只会创建一个对象?(核心逻辑)

这主要归功于 Java 的类加载机制访问控制

可以把过程想象成一个严密的关卡:

  1. 第一道关卡:私有构造方法 (private SingletonEager())
  • 这堵死了外部的路。除了 SingletonEager 自己内部,谁都不能通过 new SingletonEager() 来创建新对象。
  1. 第二道关卡:类加载机制 (Class Loading)
  • 当程序第一次用到 SingletonEager 类时(比如调用 getInstance()),JVM 会加载这个类。
  • 关键点:JVM 保证一个类只会被加载一次。
  1. 第三道关卡:静态代码块执行
  • 类加载时,JVM 自动执行 static { ... } 代码块。
  • 代码块里执行了 new SingletonEager()
  • 因为类加载只有一次,所以这个 new 动作也只有一次。

总结流程:
程序启动 -> 第一次调用 SingletonEager.getInstance() -> JVM 加载类 -> 执行静态块(创建了唯一的那个对象) -> 赋值给 static 变量 -> 返回该对象。

第二次调用 getInstance() -> 类已经加载过了 -> 直接返回 static 变量里的那个对象(不会再 new 了)。


posted @ 2026-01-28 21:32  Nickey103  阅读(13)  评论(0)    收藏  举报