Java单例模式详解:饿汉式与懒汉式的代码实现及区别
单例模式是Java中最常用的设计模式之一,旨在确保一个类只有一个实例,并提供全局访问点。本文将通过Java代码深入解析"饿汉式"与"懒汉式"两种核心实现方式,对比它们在对象创建时机、资源消耗及线程安全性上的差异,帮助开发者选择合适的实现方案。
单例模式的核心概念
单例设计模式的目的是保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。要实现这一目标,通常遵循以下四个步骤:
- 构造器私有化:防止外部直接通过
new关键字创建对象。 - 内部创建对象:在类的内部静态初始化或按需实例化该唯一对象。
- 暴露公共方法:提供一个静态的公共方法(通常命名为
getInstance),供外部获取该实例。 - 代码实现:根据需求选择具体的实现策略。
第一种实现:饿汉式(Eager Initialization)
饿汉式是在类被加载到JVM时就完成对象的创建。这种方式简单直接,不存在线程安全问题,但可能会造成资源浪费(如果对象非常庞大且可能从未被使用)。
第1步:编写饿汉式代码
以下代码演示了经典的饿汉式单例实现。我们在声明静态变量时直接实例化了对象。
package com.demo.single_;
public class test01 {
public static void main(String[] args) {
// 尝试直接new会被编译阻止,因为构造器已私有化
// girlfriend g01=new girlfriend("小红");
// 通过静态方法获取唯一实例
girlfriend t01=girlfriend.getInstance();
System.out.println(t01);
girlfriend t02=girlfriend.getInstance();
System.out.println(t02);
// 验证是否为同一对象
if(t01==t02)
System.out.println("true");
}
}
// 单例类
class girlfriend{
private String name;
// 1. 构造器私有化
private girlfriend(String name){
this.name=name;
}
// 2. 在类的内部直接创建实例(类加载时即完成)
private static girlfriend g=new girlfriend("小红");
// 3. 提供公共静态方法返回实例
public static girlfriend getInstance(){
return g;
}
@Override
public String toString() {
return "girlfriend{" +
"name='" + name + '\'' +
'}';
}
}
注意:由于对象在类加载时就被创建,如果该对象是“重量级”资源(如占用大量内存或数据库连接),而程序运行过程中并未使用它,则会造成不必要的资源浪费。
第二种实现:懒汉式(Lazy Initialization)
懒汉式是在第一次调用getInstance方法时才创建对象实例。这种方式节省内存资源,但在多线程环境下需要注意线程安全问题。
第1步:编写懒汉式代码
以下代码展示了懒汉式的实现逻辑:先定义一个null引用的静态变量,在使用时判断是否为空,为空则创建。
package com.demo.single_;
public class test02 {
public static void main(String[] args) {
// new cat("大飞"); 错误:构造器私有
System.out.println(cat.n); // 可访问静态变量
// 第一次调用,触发实例创建
cat instance=cat.getInstance();
System.out.println(instance);
// 第二次调用,直接返回已有实例
cat instance2=cat.getInstance();
System.out.println(instance2);
}
}
// 懒汉式单例类
class cat{
private String name;
// 1. 构造器私有化
private cat(String name) {
System.out.println("构造器被调用");
this.name = name;
}
// 2. 定义一个静态属性对象,初始为null
private static cat c1;
public static int n=999;
// 3. 提供public的static方法,检查并返回对象
public static cat getInstance(){
if(c1==null){
c1=new cat("大黄");
}
return c1;
}
@Override
public String toString() {
return "cat{" +
"name='" + name + '\'' +
'}';
}
}
如上所示,只有当用户使用getInstance()且对象尚未存在时,才会执行new操作。后续再次调用时,将直接返回上次创建的c1对象。
饿汉式与懒汉式的关键区别
在实际开发中,理解两者的差异有助于做出正确的技术选型:
- 创建时机不同:饿汉式在类加载阶段就创建实例;懒汉式在首次调用
getInstance方法时(使用时)才创建。 - 线程安全性:饿汉式天生安全,因为类加载过程由JVM保证线程安全;基础版懒汉式存在线程安全问题(多线程可能同时进入
if(c1==null)块从而创建多个实例)。 - 资源利用:饿汉式可能存在资源浪费(创建了但未使用);懒汉式实现了延迟加载,节省了内存空间。
- 经典案例:Java SE标准类库中的
java.lang.Runtime就是典型的单例模式应用。
以上就是Java单例模式中饿汉式与懒汉式代码实现及区别的详细内容,更多关于Java设计模式单例模式的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









