如何在java中参数化generics单例
我有下一个问题。 我有一个界面:
public interface Worker { public void start(Class taskClass); }
和单接口实现此接口:
public final class Listener implements Worker { private Listener() {} @Override public void start(Class taskClass) { ... } public static Listener getInstance() { return SingletonHolder.INSTANCE; } private static class SingletonHolder { public static final Listener INSTANCE = new Listener(); } }
我的问题是,我可以通过这种方式得到单例实例:
Worker listener = Listener.getInstance();
还是类型安全吗? 什么时候不能,如何在单例实例中使用generics?
所有generics都在运行时被剥离。
这意味着无论generics是什么,你只会有一个static class SingletonHolder
和一个INSTANCE
。
为了解决这个问题,如果有意义,你可以拥有“多个单身人士”。 您必须添加某种注册,因此如果您尝试获取一个尚未存在的注册,请在返回之前创建并存储它。 请注意,这不是编译的,可能存在一些问题,但基本方法仍然相同。
public final class Listener implements Worker { private Listener() {} @Override public void start(Class extends T> taskClass) { ... } public static Listener getInstance(Class clazz) { return SingletonHolder.INSTANCE.get(clazz); } private static class SingletonHolder { private static final Map,Listener extends Runnable> INSTANCE = new ...; } }
只是
public final class Listener implements Worker { private Listener() {} @Override public void start(Class extends Runnable> taskClass) { ... } }
显然,监听器实例可以接受任何Thread子类。
Worker worker = Listener.getInstance(); worker.start( MyThread.class );
如果要限制类型,为了阐明worker是Thread子类,则不能
Worker worker = Listener.getInstance(); // error[1]
但是你可以
Worker super Thread> worker = Listener.getInstance(); worker.start( MyThread.class ); // works for all Thread subclasses. worker.start( SomeRunnable.class ); // error; only for Thread subclasses.
如果我们讨厌通配符(我们这样做),我们可能会想要明确一个Worker
也是一个Worker
; error[1]
只是愚蠢的限制。
擦除的一个好处是,我们可以建立这种协方差。
@SuppressWarnings("unchecked") Worker worker = (Worker )(Worker) Listener.getInstance();
我们知道演员阵容对所有意图和目的都是安全的。
如果需要经常这样做,我们可以将协方差转换移动到getInstance()
以便于使用:
Worker worker = Listener.getInstance(); public final class Listener implements Worker static Listener instance = new Listener(); // it is safe to cast Worker to any Worker // as long as B is subtype of A @SuppressWarnings("unchecked") static public Worker getInstance() return (Worker )(Worker)instance;