Java泛型父类实现GetInstance出现StackOverflowError问题求助
解决单例实现中的StackOverflowError问题
嘿,我一眼就看出你代码里的问题啦——这是典型的无限递归导致栈溢出!咱们来拆解一下:
问题根源
你写的Instance类构造函数里,居然又调用了new Instance<>():
public <T> Instance() { mInstance = new Instance<>(); }
这就相当于,每次创建Instance对象时,构造函数会立刻再创建一个新的Instance,新的对象构造又会再创建一个……无限循环下去,Java虚拟机的调用栈被不断压满,最终就抛出了java.lang.StackOverflowError,也就是你看到的崩溃。
而且你这段代码的逻辑也偏离了单例的初衷:单例是要保证一个类只有一个实例,你现在反而在不断创建新实例,还把构造函数设为了公有的,外部也能随便new,完全不符合单例的设计。
修正方案:实现正确的泛型单例
根据你的需求,我给你两种常见的泛型单例实现方式,你可以根据场景选择:
方式1:所有子类共享父类的单例实例
如果你的所有子类(比如Timer)只需要共用一个父类的单例,那可以用**双重检查锁定(DCL)**来实现,保证线程安全且性能不错:
public class Instance<T> { // volatile关键字避免多线程下的指令重排问题 private static volatile Instance<?> mInstance; // 私有构造函数,禁止外部直接创建实例 protected Instance() {} @SuppressWarnings("unchecked") public static <T> Instance<T> GetInstance() { // 双重检查,减少锁竞争 if (mInstance == null) { synchronized (Instance.class) { if (mInstance == null) { mInstance = new Instance<>(); } } } return (Instance<T>) mInstance; } } public class Timer extends Instance<Timer> { // 子类可以直接继承父类的单例逻辑,无需额外代码 } // 使用方式 Timer timerInstance = (Timer) Instance.GetInstance();
方式2:每个子类拥有自己的独立单例
如果你的需求是每个子类(比如Timer)都有自己的唯一实例,那上面的方式就不适用了(因为父类静态变量是所有子类共享的)。这种情况下可以用ConcurrentHashMap来存储每个子类的实例:
import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class Instance<T> { // 用线程安全的Map存储每个子类的实例 private static final Map<Class<?>, Instance<?>> INSTANCE_CACHE = new ConcurrentHashMap<>(); // 构造函数设为protected,允许子类继承 protected Instance() {} @SuppressWarnings("unchecked") public static <T> Instance<T> GetInstance(Class<T> clazz) { // computeIfAbsent:如果缓存里没有对应实例,就创建并放入缓存 return (Instance<T>) INSTANCE_CACHE.computeIfAbsent(clazz, cls -> { try { // 通过反射创建子类实例,要求子类有可访问的无参构造 return (Instance<?>) cls.getDeclaredConstructor().newInstance(); } catch (Exception e) { throw new RuntimeException("无法创建" + cls.getName() + "的实例", e); } }); } } public class Timer extends Instance<Timer> { // 子类的构造函数可以设为protected或private(private的话需要允许反射访问) protected Timer() {} } // 使用方式 Timer timerInstance = (Timer) Instance.GetInstance(Timer.class);
额外注意点
- 原来代码里构造函数上的
<T>是多余的,会和类的泛型<T>冲突,直接去掉就好 - 单例模式一定要保证构造函数私有/受保护,避免外部随意创建实例
- 如果是多线程场景,一定要考虑线程安全问题,不然可能会创建多个实例
内容的提问来源于stack exchange,提问作者ManLok Wong
相关产品推荐
相关产品推荐

