在Java项目开发过程中,不同类之间共享同一个对象实例并调用其方法是很常见的需求,比如全局配置对象、数据库连接池实例、业务核心服务对象等,都需要保证在多个使用方之间是同一个实例,同时能够正常调用其提供的公开方法。如果采用直接new的方式创建实例,会导致多个类拿到不同的对象副本,不仅浪费资源,还可能出现数据不一致的问题。下面介绍几种优雅的实现方案。

方案一:单例模式实现实例共享
单例模式是最基础的实现方式,核心是保证一个类只有一个实例,并且提供全局访问点。常见的实现方式有饿汉式和懒汉式,下面以双重校验锁的懒汉式为例:
public class UserService {
// 私有静态实例,volatile保证多线程下的可见性和禁止指令重排
private static volatile UserService instance;
// 私有构造方法,防止外部直接new
private UserService() {}
// 全局访问方法
public static UserService getInstance() {
if (instance == null) {
synchronized (UserService.class) {
if (instance == null) {
instance = new UserService();
}
}
}
return instance;
}
// 需要被调用的业务方法
public void queryUser() {
System.out.println("查询用户信息");
}
}其他类调用时,直接通过UserService.getInstance()获取唯一实例,再调用方法即可:
public class OrderService {
public void processOrder() {
// 获取共享的UserService实例
UserService userService = UserService.getInstance();
// 调用实例方法
userService.queryUser();
}
}方案二:静态变量持有共享实例
如果不想使用单例模式的严格限制,也可以通过一个公共的持有类,用静态变量存储共享实例,适合简单的多类共享场景:
// 实例持有类
public class InstanceHolder {
// 静态变量存储共享实例,可以自定义初始化逻辑
public static ConfigService configService = new ConfigService();
}
// 配置服务类
public class ConfigService {
public String getConfig(String key) {
return "配置值:" + key;
}
}不同类直接通过InstanceHolder.configService获取实例调用方法:
public class LogService {
public void printLog() {
ConfigService config = InstanceHolder.configService;
String logLevel = config.getConfig("log_level");
System.out.println("当前日志级别:" + logLevel);
}
}
public class MonitorService {
public void checkStatus() {
ConfigService config = InstanceHolder.configService;
String switchStatus = config.getConfig("monitor_switch");
System.out.println("监控开关状态:" + switchStatus);
}
}方案三:依赖注入实现解耦共享
在Spring等框架中,依赖注入是更优雅的方式,不需要手动管理实例的创建和共享,框架会自动将同一个实例注入到需要的类中。首先定义服务类,添加@Service注解交给Spring管理:
import org.springframework.stereotype.Service;
@Service
public class PayService {
public void pay() {
System.out.println("执行支付操作");
}
}在需要使用该实例的类中,通过@Autowired注解注入同一个实例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class OrderPayService {
@Autowired
private PayService payService;
public void handleOrderPay() {
payService.pay();
}
}
@Service
public class RefundService {
@Autowired
private PayService payService;
public void handleRefund() {
payService.pay();
}
}Spring默认管理的Bean都是单例的,所以OrderPayService和RefundService中注入的PayService是同一个实例,无需额外处理共享逻辑。
不同方案的选择建议
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 单例模式 | 无框架的小型项目,需要严格控制实例数量 | 实现简单,不需要额外依赖 | 代码耦合度高,不方便单元测试 |
| 静态变量持有 | 简单共享场景,实例初始化逻辑简单 | 使用直观,容易理解 | 静态变量生命周期长,不适合需要动态销毁的场景 |
| 依赖注入 | 使用Spring等框架的中大型项目 | 解耦性好,方便测试和维护,无需手动管理实例 | 需要依赖框架,小型项目会增加复杂度 |
注意事项
- 共享的对象实例如果是可变状态的,要注意多线程下的线程安全问题,必要时添加同步机制
- 不要过度使用全局共享实例,避免代码出现过高的耦合度,增加维护难度
- 使用单例模式时,要避免实现
Cloneable接口,防止通过克隆创建新的实例副本 - 依赖注入场景下,如果需要非单例的共享实例,可以调整Bean的作用域,比如设置为
prototype后配合自定义作用域实现共享
在实际开发中,优先根据项目规模和使用的技术栈选择合适的方案,中大型项目建议优先使用依赖注入的方式,既保证实例共享的优雅性,也便于后续的扩展和维护。